In Python (3+) it is impossible to create a class which is not a subclass of object. This means that the protocols associated with the class and instances of the class are tightly bound to object. Metaclasses provide a way to extend this so as to have additional domain-specific protocols.
The snippet below shows how this may be accomplished by overriding the type.__init__() during metaclass definition. The metaclass will have a collection of methods that will be hooked into the class once it is created. These methods may then be used to implement the domain-specific protocols.
# the metaclass
class Meta(type):
def __init__(self, name, bases, class_dict):
# since this is init the class has already been created
# we introduce some arbitrary 'fire' protocol which will be invoked
# using some 'fire()' function
self.__fire__ = self._fire
type.__init__(self, name, bases, class_dict)
def _fire(self, *args, **kwargs):
print('args: ', args)
print('kwargs: ', kwargs)
def fire(obj, *args, **kwargs):
obj.__fire__(*args, **kwargs)
# now we can create classes based on this metaclass
class X(object, metaclass=Meta):
pass
x = X()
# their MRO still includes object
print('X.__mro__:', X.__mro__)
# both the class and instances will support the fire protocol
print('dir(x):', dir(x))
print('dir(X):', dir(X))
# even subclasses will and their instances will support the fire protocol
class XX(X):
pass
xx = XX()
print('XX.__mro__:', XX.__mro__)
print('dir(xx):', dir(xx))
print('dir(XX):', dir(XX))
# they are NOT of type 'type'
print('type(X)', type(X))
print('type(XX)', type(XX))