Python Book
πŸ‡ΊπŸ‡¦ Stand with UkraineπŸŽ“Training Suite
  • Book overview
  • Notes about this book
  • 1. Introduction to Python
    • What is Python
    • Basic syntax
    • Objects in Python
    • Python overview
    • Installation, IDEs etc.
    • ipython
    • Sources for self-learning
  • 2. Strings and numbers
    • Getting help
    • Introspection
    • Basic types
    • None object
    • Numbers
    • Strings
    • Unicode
    • String Formatting
    • Regular expressions
    • Sources for self-learning
  • 3. Containers
    • Data Structures
    • Lists
    • Tuples
    • Dictionaries
    • Sets
    • Conditions
    • Loops
    • Additional modules
    • Sources for self-learning
  • 4. Functions
    • Functions
    • Scopes of visibility
    • Generators
    • Lambdas
    • Type hints
    • Function internals
    • Sources for self-learning
  • 5. Functional Programming
    • Builtins
    • Iterable
    • Iterator
    • Functional Programming
    • Functools
    • Comprehensions
    • Additional modules
    • Sources for self-learning
  • 6. Code Styling
    • Zen of Python
    • Lint
    • PEP 8
    • Modules
    • Packages
    • Sources for self-learning
  • 7. OOP
    • OOP Basics
    • Code design principles
    • Classes
    • Method Resolution Order
    • Magic attributes and methods
    • Super
    • Sources for self-learning
  • 8. Decorators, Exceptions
    • Decorators
    • Exceptions
    • Sources for self-learning
  • 9. Testing
    • Basic Terminology
    • Testing theory
    • Dev unit testing vs QA automated testing
    • Best Practices
    • Doctest
    • Unittest
    • Test Runners
    • Pytest
    • Nose
    • Continuous Integration
  • 10. System Libs
    • Working with files
    • System libraries
    • Subprocess
    • Additional CLI libraries
Powered by GitBook
On this page
  • Old style class MRO
  • New style class MRO
  • Caveats

Was this helpful?

Edit on Git
  1. 7. OOP

Method Resolution Order

For old classes (in Python 2 only) it was vertical-then-horizontal order of looking up for object attributes/methods.

For Python 3.x and for New style classes (Python 2.5+) MRO is horizontal-then-vertical order.

Old style class MRO

Just for information as it is used only in Python 2! It is helpful to understand how MRO works now though.

class A: 
    x = 'from A'

class B(A): 
    pass

class C(A): 
    x = 'from C'

class D(B, C): 
    pass
print(D.x)
'from A'

So as you can see value of C.x is ignored even if it is "closer". This was completely redesigned.

The old MRO builds a list of classes to search for methods. This algorithm is a tree routing:

Deep first, from left to right

  1. Look if method exists in instance class

  2. If not, looks if it exists in its first parent, then in the parent of the parent and so on

  3. If not, it looks if current class inherits from others classes up to the current instance others parents.

New style class MRO

The problem with old style classes is that if we going to inherit from base object we wouldn't be able to change anything. All because the logic of searching was too simple and wasn't designed for the case where everything is inherited from object.

πŸͺ„ Code:

class A:  # class A(object):   <--- in Python 2.5+
    x = 'from A'

class B(A):
    pass
    
class C(A): 
    x = 'from C'

class D(B, C):
    pass
     
print(D.x)
print(D.__mro__)
print(D.mro())

πŸ“Ÿ Output:

from C
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

Difference to old MRO is the additional check done each time before adding some class to the search path. The check is:

  • Is this class is the parent for some other class in the search path that will be added soon?

If yes β†’ then it is been shifted after it's inherited class in order to not shadow it's methods.

It can be described in one sentence as:

Deep first, from left to right with additional check and shifting the class that is parent for next classes after them.

The result of MRO linearization is stored in attribute __mro__.

πŸͺ„ Code:

print(D.__mro__) # D.mro()

πŸ“Ÿ Output:

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

So, Python 2 would build this MRO:

D, B, A, C, A

We see that A is repeated, so removing first one keeping the last one will be Python 3's MRO:

D, B, C, A

πŸͺ„ Code:

class A(object): 
    x = 1
class B(): pass
class A1(A): pass
class B1(B):
    x = 2
class C(A1, B1): pass
class C1: pass
class D(C, C1): pass

#C.__mro__
D.mro()

πŸ“Ÿ Output:

[__main__.D,
 __main__.C,
 __main__.A1,
 __main__.A,
 __main__.B1,
 __main__.B,
 __main__.C1,
 object]

πŸͺ„ Code:

class A: pass
class B(A): pass
class C(B): pass
class D(B): pass
class E(C): pass
class F(D, E, B): pass

print(F.__mro__)

πŸ“Ÿ Output:

(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

What's important to know about C3 is that it guarantees three important features:

  • Subclasses appear before base classes

  • Base class declaration order is preserved

  • For all classes in an inheritance graph, the relative orderings guaranteed by 1 and 2 are preserved at all points in the graph.

Caveats

Sometimes the MRO can not be built:

Another example where object is used before the class which inherites from it which confuses the logic:

πŸͺ„ Code:

class A: pass
class B(object, A): pass

πŸ“Ÿ Output:

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Input In [102], in <cell line: 2>()
----> 2 class B(object, A): pass


TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, A
PreviousClassesNextMagic attributes and methods

Last updated 2 years ago

Was this helpful?

This new algorithm (used by default in Python 3 and in Python 2 - from 2.2 when subclassing object) is called in case of multiple inheritance to build an order of inheritance hierarchy in which it will search for matching method/attribute.

C3-linearization