skip to content

What does a Python class's `__mro__` tuple contain, and why does `object` end it?

level: middleimportance: should knowfreq 46%

answer

  1. A cached tuple of classes
  2. Each ancestor listed once
  3. Class first, root last
  4. No ancestor before its own subclass
  5. `mro()` returns a fresh list

basics

~10 s

Cls.__mro__ holds the class itself followed by every ancestor exactly once, in lookup order. object is last because every class inherits from it, and no ancestor may precede one of its own subclasses.

solid answer

~40 s

`Cls.__mro__` is a tuple, computed once at class creation, that starts with the class itself and lists every ancestor exactly once — even one reached by several inheritance paths — in the order attribute lookup will consult them. `object` is the final entry in Python 3 because every class ultimately derives from it and the linearization rules forbid a class appearing before any of its subclasses, so the universal root can only sit at the end. `Cls.mro()` returns the same sequence as a fresh `list` rather than the cached tuple, and `inspect.getmro(Cls)` is the introspection spelling. Reading the tuple left to right is literally reading the search order: lookup takes the first class whose own namespace defines the name.

code

pycon · 9 lines
pycon
>>> class A: pass
...
>>> A.__mro__
(<class '__main__.A'>, <class 'object'>)
>>> A.mro()
[<class '__main__.A'>, <class 'object'>]
>>> import inspect
>>> inspect.getmro(A) == A.__mro__
True

go deeper

for a junior

Know that every class carries __mro__, that printing it shows the lookup order, and that the class itself is first while object is last. Being able to read one is the bar here.

for a middle

Explain the guarantees — each ancestor exactly once, subclasses always before their bases — and the difference between the cached __mro__ tuple and the list returned by mro().

for a senior

Demonstrate the debugging habit: reach for the MRO when an inherited implementation is not the one you expected, and read the position of each class rather than re-reading method bodies.

for a principal

Frame it as the contract that makes multiple inheritance reviewable: if a team cannot predict a class's order without printing it, the hierarchy is too deep and the fix is structural, not a reordering of bases.

### What is actually in the tuple `Cls.__mro__` is a `tuple` of class objects: `Cls` itself first, then all of its ancestors, then `object`. Three properties are guaranteed: 1. **Every ancestor appears exactly once**, no matter how many inheritance paths lead to it. A diamond's shared base is listed one time, not once per branch. 2. **The class itself is first**, so its own definitions always win over anything inherited. 3. **`object` is last.** In Python 3 every class derives from `object`, and the linearization rules forbid a class from appearing ahead of any of its subclasses; since `object` is a superclass of everything else in the tuple, the only position it can legally occupy is the final one. The tuple is computed once, while the class statement executes, and cached on the class. Attribute lookup that has to consult the hierarchy scans it left to right and stops at the first class whose own namespace contains the name. ### `__mro__` versus `mro()` ```pycon >>> class A: pass ... >>> A.__mro__ (<class '__main__.A'>, <class 'object'>) >>> A.mro() [<class '__main__.A'>, <class 'object'>] ``` `__mro__` is the cached tuple — read it when you just want to look. `mro()` is a method on the type that returns a new `list` each call; it is also the hook the machinery calls when it needs the order computed, which is why a metaclass can override it to produce a custom linearization. Because it hands back a fresh mutable list, mutating the result changes nothing about the class. `inspect.getmro(Cls)` returns the tuple and is the form to reach for in tooling, since it works uniformly for anything class-like. A detail worth having straight: `Cls.mro` is a method of the *metaclass*, so it is available on classes but not on instances — `A().mro()` fails unless the class itself defines such a method. `A().__class__.__mro__` or `type(a).__mro__` is the instance-side spelling. ### Reading a real one ```python from collections import OrderedDict [c.__name__ for c in OrderedDict.__mro__] # ['OrderedDict', 'dict', 'object'] ``` The practical habit is: when a hierarchy surprises you, print the MRO before theorising. It tells you, in one line, which class will supply each inherited name and where a cooperative call chain will go next. It is also the fastest way to spot an accidental base ordering — if a class you expected to specialise behaviour shows up *after* the generic base it was meant to override, the order, not the method body, is your bug. ### Why the shape matters Because the order is a total, linear order over all ancestors, questions that would be ambiguous in a raw graph become mechanical. "Which `__init__` runs?" is answered by scanning left to right. "What comes after this class in a cooperative chain?" is the next tuple element, and crucially that is a property of the *instance's* class, not of the class the code is written in — the same method body can hand off to different classes depending on whose MRO is in play. Two boundaries are worth naming. First, the MRO is about *classes*: an instance's own attribute dictionary is consulted first for ordinary attributes and does not appear in the tuple at all. Second, it lists what exists at class-creation time; classes created later that subclass `Cls` get their own tuples, and `Cls.__mro__` is unaffected. ### Failure mode The tuple is not merely descriptive — it is produced by an algorithm that can fail. If the constraints implied by the base list cannot all be satisfied, the class statement itself raises a `TypeError` and no class object is ever created, which is why you never see a malformed `__mro__`. Every tuple you can read is, by construction, a consistent one: class first, each ancestor once, subclasses before their bases, and `object` at the end. ### It is read-only, and it is a cache key `__mro__` cannot be assigned: `A.__mro__ = ()` raises `AttributeError: attribute '__mro__' of 'type' objects is not writable`. You cannot repair a hierarchy by rewriting the tuple, and you should not try — the supported way to influence the order is the base list, or a metaclass that overrides `mro()` before the class exists. CPython also keeps a per-type method cache keyed on this order, so the tuple's stability is what makes attribute lookup fast: the scan is short and its result is remembered until something in the hierarchy changes. A last detail that trips people: the tuple contains class *objects*, not names, so two same-named classes from different modules are distinct entries. Comparing MROs across a reload of a module will show classes that print identically but are not equal, which is usually the explanation when an `isinstance` check fails against a class that looks exactly right.

  • How does a shared base appear in the tuple when two branches both inherit it?
    Exactly once, positioned after both branches. The linearization deduplicates ancestors rather than listing a class per path, and it places a class after every one of its subclasses, so a diamond's common base sits between the two branches and `object`.
  • Why can you call `SomeClass.mro()` but not `some_instance.mro()`?
    `mro` is defined on `type`, the metaclass, so it is found when the lookup starts on a class object. An instance's lookup starts on its own class and never consults the metaclass, so the name is not visible there. Use `type(obj).__mro__` instead.
  • Can `__mro__` ever be inconsistent — say, a base listed before its own subclass?
    No. The order is produced by the linearization algorithm at class creation, and if no order satisfying the constraints exists, the class statement raises a `TypeError` and no class is created. Every readable `__mro__` is consistent by construction, and the attribute is read-only.

saying these in an interview costs you the question

  • Says a diamond's shared base is listed once per path
  • Thinks `__mro__` lists only the direct bases
  • Claims `mro()` and `__mro__` return the same object
  • Believes the tuple is rebuilt on each attribute access
  • Says `object` appears first as the root of the hierarchy

context