Overview
Currently, the following meta-classes are provided:
See also
- Meta Classes
- Python Data Model
General Data Model of Python and section about __slots__.
ExtendedType
The new meta-class ExtendedType allows to implement singletons,
slotted types and combinations thereof.
Since Python 3, meta-classes are applied in a class definition by adding a named parameter called metaclass to the
list of derived classes (positional parameters). Further named parameters might be given to pass parameters to that new
meta-class.
class MyClass(metaclass=ExtendedType):
pass
Slotted
Mixin
Abstract Class
A class containing an abstract method cannot be instantiated, but some classes have nothing to mark abstract and still exist only to be derived from - a base-class collecting shared infrastructure, for instance.
The @abstractclass decorator declares a class as abstract (inheritance tree inner
node) without the need for abstract methods.
Example:
from pyTooling.MetaClasses import ExtendedType, abstractclass
@abstractclass
class Base(metaclass=ExtendedType):
def Method(self) -> None:
...
class Derived(Base):
pass
Derived() # fine
The decorator sets __abstractClass__ on the class and recomputes __isAbstract__, which is the same
computation ExtendedType runs for abstract methods.
The marker belongs to the decorated class alone: ExtendedType clears it on every
class it creates, so a derived class is concrete again unless it is decorated itself or inherits an abstract
method. The declaration therefore describes one class rather than a branch of the hierarchy.
See also
@abstractmethod→ Mark a method as abstract, which makes its class abstract as a consequence.
Abstract Method
The @abstractmethod decorator marks a method as abstract. The original method gets
replaced by a method raising a NotImplementedError. When a class containing abstract methods is
instantiated, an AbstractClassError is raised.
Example:
class A(metaclass=ExtendedType):
@abstractmethod
def method(self) -> int:
"""Methods documentation."""
class B(A):
@InheritDocString(A)
def method(self) -> int:
return 2
Hint
If the abstract method should contain code that should be called from an overriding method in a derived class, use the @mustoverride decorator.
MustOverwrite Method
The @mustoverride decorator marks a method as must override. When a class containing
must override methods is instantiated, an MustOverrideClassError is raised.
In contrast to @abstractmethod, the method can still be called from a derived class implementing an overridden method.
Example:
class A(metaclass=ExtendedType):
@mustoverride
def method(self) -> int:
"""Methods documentation."""
return 2
class B(A):
@InheritDocString(A)
def method(self) -> int:
result = super().method()
return result + 1
Hint
If the method contain no code and throw an exception when called, use the @abstractmethod decorator.
Singleton
A class defined with enabled singleton behavior implements the singleton design pattern,
which allows only a single instance of that class to exist. If another instance is going to be created, a previously
cached instance of that class will be returned.
class MyClass(metaclass=ExtendedType, singleton=True):
pass
Example Usage
class Terminal(metaclass=ExtendedType, singleton=True):
def __init__(self) -> None:
pass
def WriteLine(self, message):
print(message)
Slotted Type
A class defined with enabled slots behavior stores instance fields in slots. The meta-class, translates all
type-annotated fields in a class definition into slots. Slots allow a more efficient field storage and access compared
to dynamically stored and accessed fields hosted by __dict__. This improves the memory footprint as well as the
field access performance of all class instances. This behavior is automatically inherited to all derived classes.
class MyClass(metaclass=ExtendedType, slots=True):
pass
Example Usage
class Node(metaclass=ExtendedType, slots=True):
_parent: "Node"
def __init__(self, parent: "Node" = None) -> None:
self._parent = parent
root = Node()
node = Node(root)
SlottedObject
A class definition deriving from SlottedObject will bring the slotted type behavior to
that class and all derived classes.
Deriving from |
Apply |
Deriving from |
|---|---|---|
class MyClass(SlottedObject):
pass
|
@slotted
class MyClass(SlottedObject):
pass
|
class MyClass(metaclass=ExtendedType, slots=True):
pass
|
Overloading
Warning
This needs a clear definition before overloading makes sense…
This class provides a method dispatcher based on method signature’s type annotations.
Example Usage
class A(metaclass=Overloading):
value = None
def __init__(self, value : int = 0) -> None:
self.value = value
def __init__(self, value : str) -> None:
self.value = int(value)
a = A()
print(a.value)
b = A(3)
print(b.value)
c = A("42")
print(c.value)