Week 5 - Object Model Deep Dive: Classes, Descriptors, Metaclasses¶
5.1 Conceptual Core¶
- Attribute lookup is a protocol, not a field read.
obj.xcallstype(obj).__getattribute__(obj, "x"), which checks the data-descriptor chain on the type, then the instance dict, then non-data descriptors, then__getattr__. - Descriptors (
__get__,__set__,__delete__) are how@property,staticmethod,classmethod, and__slots__actually work. Understanding descriptors is understanding 80% of Python's "magic." - Metaclasses (
typeis the default) intercept class creation. They are over-used;__init_subclass__(PEP 487) and class decorators cover most legitimate use cases.
5.2 Mechanical Detail¶
__slots__: replaces the per-instance__dict__with a fixed-size struct of slot descriptors. Saves ~40–60% memory per instance and speeds attribute access. Cost: no dynamic attributes, multiple-inheritance gotchas. Mandatory in hot-path data classes.- MRO (method resolution order) and the C3 linearization:
MyClass.__mro__. Diamond inheritance is solvable but signals over-design. super(): a proxy object that walks the MRO oftype(self)starting after the current class. Always cooperative; do not passsuper()__init__arguments unless you know the MRO.@property,@cached_property(3.8+, requires writable__dict__- incompatible with default__slots__unless you slot__dict__).__init_subclass__(cls, **kwargs)runs at subclass creation. Used for plugin registration, validation of subclass invariants. The 90%-case alternative to a metaclass.
5.3 Lab - "Build a Tiny ORM"¶
- Implement a
Fielddescriptor with type validation and adefault.class User: name = Field(str); age = Field(int, default=0). - Use
__init_subclass__to collect declared fields intocls._fields. Auto-generate__init__and__repr__. - Compare your hand-rolled version to
@dataclass(slots=True). Note where dataclass is better (PEP-595 ordering,__eq__,__hash__). - Implement a
RegistryMetametaclass that records every subclass in a class-level dict. Then re-implement using__init_subclass__. Defend the simpler version in writing.
5.4 Idiomatic & Linter Drill¶
- Enable
ruffSLOTrule. Add__slots__to every internal data class in your project. Note size delta withpympler.asizeof.
5.5 Production Hardening Slice¶
- Add
pyrightstrict mode. Addfrom __future__ import annotationsand switch to PEP 604 union syntax (X | Y). Resolve all type errors.