Study notes · 10% of the exam

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. 1

    Assignment never copies: b = a binds a second name to the same object. Use copy.copy, slicing or list() for a shallow copy, and copy.deepcopy when nested objects must be independent too.

  2. 2

    is tests identity and == tests value (via __eq__). Use is only for singletons such as None; small-int caching (-5 to 256) and string interning are CPython details.

  3. 3

    x += y calls __iadd__ when it exists (lists extend in place, so aliases see the change) and otherwise falls back to x = x + y (strings, tuples and numbers rebind). The result is always assigned back, so __iadd__ must return self.

  4. 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.0 and True are the same dict key.

  5. 5

    Binary operators try a.__op__(b), then b.__rop__(a), then raise TypeError; return NotImplemented, not an exception, for unsupported types. If b's type is a subclass that overrides the reflected method, it is tried first. == and != fall back to identity instead of raising.

  6. 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. 7

    Floor division and % round toward negative infinity (-7 // 2 == -4, -7 % 2 == 1), and comparison operators including in and is chain: a < b > c means a < b and b > c.

Common traps

  • [[0] * 3] * 3 repeats 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.

Test yourself on Data Model, Identity and Mutability

Ten questions, with the answer and explanation after each one.