Skip to content

The data model

Senior

Dunder methods, attribute lookup, and how Python's object protocols fit together.

2 questions · answers hidden

  1. 01How does attribute lookup work for `obj.x`?

    Roughly, for an instance:

    1. Python looks up type(obj).__mro__ for a data descriptor named x (defines __set__/__delete__, e.g. property). If found, its __get__ wins.
    2. Otherwise it checks obj.__dict__ for x.
    3. Otherwise it checks the class MRO again for a non-data descriptor (e.g. a plain function, which becomes a bound method) or a plain class attribute.
    4. Otherwise it calls type(obj).__getattr__(obj, "x") if defined, else raises AttributeError.

    __getattribute__ is what actually runs this whole algorithm; __getattr__ is only the fallback for the miss case.

    #q-how-does-attribute-lookup-work-for-objx
  2. 02What's the difference between `__str__`, `__repr__`, and when is each used?
    • __repr__ is for developers: unambiguous, ideally eval-able, shown in the REPL, in containers ([obj]), and by the debugger. Always define it.
    • __str__ is for end users / readable output; used by str() and print(). Falls back to __repr__ if not defined.

    A good default __repr__ is f"{type(self).__name__}(name={self.name!r})".

    #q-whats-the-difference-between-__str__-__repr__-and-when-is-ea