Data Model, Identity and Mutability
Names are bindings to objects, and nearly every operator calls a special method on the object's type. Know when an operation mutates versus rebinds, how hashing and equality must agree, and how attribute lookup works so you can predict the tricky cases.
Key points
- 1
Assignment never copies:
b = abinds a second name to the same object. Usecopy.copy, slicing orlist()for a shallow copy, andcopy.deepcopywhen nested objects must be independent too. - 2
istests identity and==tests value (via__eq__). Useisonly for singletons such asNone; small-int caching (-5 to 256) and string interning are CPython details. - 3
x += ycalls__iadd__when it exists (lists extend in place, so aliases see the change) and otherwise falls back tox = x + y(strings, tuples and numbers rebind). The result is always assigned back, so__iadd__must returnself. - 4
Equal objects must have equal hashes. Defining
__eq__without__hash__makes a class unhashable, and mutating a field that the hash depends on strands the object inside sets and dicts.1,1.0andTrueare the same dict key. - 5
Binary operators try
a.__op__(b), thenb.__rop__(a), then raise TypeError; returnNotImplemented, not an exception, for unsupported types. Ifb's type is a subclass that overrides the reflected method, it is tried first.==and!=fall back to identity instead of raising. - 6
Attribute lookup order: data descriptors on the type (property, anything with
__set__), then the instance__dict__, then non-data descriptors and class attributes (functions), then__getattr__as a last resort. - 7
Floor division and
%round toward negative infinity (-7 // 2 == -4,-7 % 2 == 1), and comparison operators includinginandischain:a < b > cmeansa < b and b > c.
Common traps
[[0] * 3] * 3repeats one inner list three times, so writing to one row changes every row; build rows with a comprehension.t[0] += [1]on a tuple holding a list raises TypeError but still extends the list, because the in-place add runs before the failed item assignment.An AttributeError raised inside a property getter triggers
__getattr__for the property's name, hiding the real bug.
Read the source
Test yourself on Data Model, Identity and Mutability
Ten questions, with the answer and explanation after each one.