Classes, Inheritance and the MRO
Know how attribute lookup, method binding and the MRO really work, and how dataclasses, enums, ABCs and class-creation hooks build on them.
Key points
- 1
Class attributes are shared; assigning through an instance (even with
+=) creates an instance attribute that shadows the class one. - 2
Functions become bound methods via the descriptor protocol; every access creates a new bound method, so compare with
==, notis. - 3
The MRO comes from C3 linearization: subclasses before bases, declared base order preserved, or a TypeError if impossible.
- 4
super()means the next class in the MRO of the instance, so cooperative__init__methods must forward**kwargs. - 5
dataclass rejects mutable defaults, orders fields with defaults last, removes
__hash__unless frozen, and builds a new class forslots=True. - 6
Enum members are singletons; duplicate values create aliases, and plain Enum never equals its raw value (IntEnum and StrEnum do).
- 7
Prefer
__init_subclass__and class decorators to metaclasses; reach for a metaclass only to control__call__,__prepare__or class creation itself.
Common traps
A class that defines
__eq__without__hash__becomes unhashable.Implicit dunder calls such as
len(proxy)bypass__getattr__, so delegation proxies must define those methods explicitly.Zero-argument
super()needs the compiler-made__class__cell, so it fails in functions attached after class creation and in@dataclass(slots=True)methods on 3.13.
Read the source
Test yourself on Classes, Inheritance and the MRO
Ten questions, with the answer and explanation after each one.