# our metaclass classMultiBases(type): # overriding __new__ method def__new__(cls, clsname, bases, clsdict): # if no of base classes is greater than 1 # raise error iflen(bases)>1: raise TypeError("Inherited multiple base classes!!!") # else execute __new__ method of super class, ie. # call __init__ of type class returnsuper().__new__(cls, clsname, bases, clsdict) # metaclass can be specified by 'metaclass' keyword argument # now MultiBase class is used for creating classes # this will be propagated to all subclasses of Base classBase(metaclass=MultiBases): pass # no error is raised classA(Base): pass # no error is raised classB(Base): pass # This will raise an error! classC(A, B): pass
输出:
1 2 3 4
Traceback (most recent call last): File "<stdin>", line 2, in <module> File "<stdin>", line 8, in __new__ TypeError: Inherited multiple base classes!!!
from functools import wraps defdebug(func): '''decorator for debugging passed function''' @wraps(func) defwrapper(*args, **kwargs): print("Full name of this method:", func.__qualname__) return func(*args, **kwargs) return wrapper defdebugmethods(cls): '''class decorator make use of debug decorator to debug class methods ''' for key, val invars(cls).items(): ifcallable(val): setattr(cls, key, debug(val)) return cls classdebugMeta(type): '''meta class which feed created class object to debugmethod to get debug functionality enabled objects''' def__new__(cls, clsname, bases, clsdict): obj = super().__new__(cls, clsname, bases, clsdict) obj = debugmethods(obj) return obj # base class with metaclass 'debugMeta' # now all the subclass of this # will have debugging applied classBase(metaclass=debugMeta):pass # inheriting Base classCalc(Base): defadd(self, x, y): return x+y # inheriting Calc classCalc_adv(Calc): defmul(self, x, y): return x*y # Now Calc_adv object showing # debugging behaviour mycal = Calc_adv() print(mycal.mul(2, 3))
classTerminateMeta(type): def__new__(metacls, cls, bases, classdict): type_list = [type(base) for base in bases]
for typ in type_list: if typ is metacls: raise RuntimeError( f"Subclassing a class that has " + f"{metacls.__name__} metaclass is prohibited" ) returnsuper().__new__(metacls, cls, bases, classdict)
# key is attribute name and val is attribute value in attribute dict for key, val in classdict.items(): ifisinstance(val, FunctionType) orisinstance(val, MethodType): setattr(new_cls, key, timefunc(val)) return new_cls
# key is attribute name and val is attribute value in attribute dict for key, val in classdict.items(): ifisinstance(val, FunctionType) orisinstance(val, MethodType): setattr(new_cls, key, exc_handler(val)) return new_cls
classBase(metaclass=ExceptionMeta): pass
classCalc(Base): defadd(self, x, y): return x + y
classCalcAdv(Calc): defdiv(self, x, y): return x / y
from dataclasses import dataclass from datetime import datetime
classEventMeta(type): def__new__(metacls, cls, bases, classdict): """__new__ is a classmethod, even without @classmethod decorator Parameters ---------- cls : str Name of the class being defined (Event in this example) bases : tuple Base classes of the constructed class, empty tuple in this case attrs : dict Dict containing methods and fields defined in the class """ new_cls = super().__new__(metacls, cls, bases, classdict)
Metaclasses are deeper magic that 99% of users should never worry about. If you wonder whether you need them, you don’t (the people who actually need them know with certainty that they need them, and don’t need an explanation about why).