First steps
Type system reference
Configuring and running mypy
Miscellaneous
Project Links
Ametaclass is a class that describesthe construction and behavior of other classes, similarly to how classesdescribe the construction and behavior of objects.The default metaclass istype, but it’s possible to use other metaclasses.Metaclasses allows one to create “a different kind of class”, such asEnums,NamedTuples and singletons.
Mypy has some special understanding ofABCMeta andEnumMeta.
classM(type):passclassA(metaclass=M):pass
Mypy supports the lookup of attributes in the metaclass:
fromtypingimportClassVar,TypeVarS=TypeVar("S")classM(type):count:ClassVar[int]=0defmake(cls:type[S])->S:M.count+=1returncls()classA(metaclass=M):passa:A=A.make()# make() is looked up at M; the result is an object of type Aprint(A.count)classB(A):passb:B=B.make()# metaclasses are inheritedprint(B.count+" objects were created")# Error: Unsupported operand types for + ("int" and "str")
Note that metaclasses pose some requirements on the inheritance structure,so it’s better not to combine metaclasses and class hierarchies:
classM1(type):passclassM2(type):passclassA1(metaclass=M1):passclassA2(metaclass=M2):passclassB1(A1,metaclass=M2):pass# Mypy Error: metaclass conflict# At runtime the above definition raises an exception# TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its basesclassB12(A1,A2):pass# Mypy Error: metaclass conflict# This can be solved via a common metaclass subtype:classCorrectMeta(M1,M2):passclassB2(A1,A2,metaclass=CorrectMeta):pass# OK, runtime is also OK
Mypy does not understand dynamically-computed metaclasses,such asclassA(metaclass=f()):...
Mypy does not and cannot understand arbitrary metaclass code.
Mypy only recognizes subclasses oftype as potential metaclasses.
Self is not allowed as annotation in metaclasses as perPEP 673.
For some builtin types, mypy may think their metaclass isabc.ABCMetaeven if it istype at runtime. In those cases, you can either:
useabc.ABCMeta instead oftype as thesuperclass of your metaclass if that works in your use-case
mute the error with#type:ignore[metaclass]
importabcasserttype(tuple)istype# metaclass of tuple is type at runtime# The problem:classM0(type):passclassA0(tuple,metaclass=M0):pass# Mypy Error: metaclass conflict# Option 1: use ABCMeta instead of typeclassM1(abc.ABCMeta):passclassA1(tuple,metaclass=M1):pass# Option 2: mute the errorclassM2(type):passclassA2(tuple,metaclass=M2):pass# type: ignore[metaclass]