__slots__ replaces per-instance __dict__ with fixed named slots, preventing dynamic attribute assignment and reducing memory and attribute lookup overhead.
Inside CPython's attribute lookup - Antonio Cuni's blog
Attribute lookup in Python is more complex than checking instance __dict__ then type; descriptors, instance vs type lookup, and metaclasses affect behavior.