Metaclasses

class MyMeta(type): """ We define a meta class: a meta class is a class describing what a class is. """ def __new__(mcs, name, bases, dct): """ called when the class is created :param mcs: the meta-class :param name: the name of the class that is created :param bases: :param dct: """ print(f'mcs: {mcs}\n name: {name}\n bases: {bases} \n dct: {dct}') return type.__new__(mcs, name, bases, dct) def __init__(self, *args, **kwargs): print(f'self: {self}\n args: {args}\n kwargs: {kwargs}') return type.__init__(self, *args, **kwargs) class MyClass(metaclass=MyMeta): pass # Instantiate the class #my_instance = MyClass()
mcs: <class '__main__.MyMeta'> name: MyClass bases: () dct: {'__module__': '__main__', '__qualname__': 'MyClass'} self: <class '__main__.MyClass'> args: ('MyClass', (), {'__module__': '__main__', '__qualname__': 'MyClass'}) kwargs: {}

Example of documentation checker

class MetaClassWithDoc(type): """ This meta-class is like type but it checks at the creation (in __new__ of the class) that all methods have a docstring (__doc__ field is defined) """ def __new__(cls, name, bases, dct): for attr, value in dct.items(): if callable(value) and not value.__doc__: raise TypeError(f'Method {attr} must have a docstring') return super().__new__(cls, name, bases, dct) class DocumentedClass(metaclass=MetaClassWithDoc): """ All methods of this class should be documented. Otherwise, BOOM. """ def method_with_docstring(self): """This method is documented.""" pass # def method_without_docstring(self): # pass # This will raise a TypeError

Example of timed classes

import types from time import time class TimerMetaClass(type): """ meta-class for classes with methods that are timed """ def __new__(mcs, name, bases, dct): def getTimedVerionOfMethod(name, method): def timedVersionFunctionOfMethod(self, *args, **kwargs): t = time() result = method(self, *args, **kwargs) print("Appel de %s :\t%s" % (name, time() - t)) return result timedVersionFunctionOfMethod.__name__ = method.__name__ timedVersionFunctionOfMethod.__doc__ = method.__doc__ timedVersionFunctionOfMethod.__dict__ = method.__dict__ return timedVersionFunctionOfMethod d = {} for name, slot in dct.items(): if type(slot) is types.FunctionType: d[name] = getTimedVerionOfMethod(name, slot) else: d[name] = slot return type.__new__(mcs, name, bases, d) class A(metaclass=TimerMetaClass): def m(self): pass a = A() a.m()