MRO rules in multiple inheritance in Python

Tram Ho

If you really want to know how multi-inheritance in Python works, then this article is for you. Let’s start with some definitions:

  1. For a C class in a complex inheritance hierarchy, determining the order of overridden methods is an important task, to determine the order of C’s ancestors.
  2. The list of ancestors of a C class, including the class itself, sorted from the closest to the most distant ancestors, is called the class priority list or the linearization of C.
  3. Method Resolution Order (MRO) is a set of rules for building an inheritance tree. MRO of C means the successor of C class.
  4. For example, in the case of a single inheritance hierarchy, if C is a subclass of C1 and C1 is a subclass of C2, then the linearization of C is simply a list [C, C1, C2]. However, with many inheritance hierarchies, the linearization construction becomes more cumbersome, because the linearization construction respecting local and monotonous priority order is more difficult.
  5. Definition of monotony. A MRO is monotonous when the following is true: if C1 precedes C2 in C inheritance tree, then C1 comes before C2 in the inheritance tree of any subclass of C. On the other hand, creating a new class has It is possible to change the resolution order of the methods, potentially causing very subtle errors. An example of this happening will be shown later.
  6. Not all classes are linear. There are cases, in complex hierarchies, in which a class cannot be obtained so that its linearization complies with all the above definitions. For example :

can be represented by the following inheritance diagram, which I have denoted with O class object, which is the beginning of any hierarchy.

In this case, it is not possible to derive a new C class from A and B, since X precedes Y in A, but Y precedes X in B, so the order of method resolution is not clear in C.

MRO rules

Let me introduce a few simple symbols that will be useful for the following discussion. I will use abbreviations:

to denote the list of classes [C1, C2, …, CN]. The top of the list is its first element and the rest is its tail. I also use the notation:

to express the result of merging 2 lists [C] + [C1, C2, …, CN]. Now I will explain how MRO works: Consider a C class in the inheritance hierarchy, with C inheriting from the base classes B1, B2, …, BN. We want to calculate the linearization L [C] of class C. The rule is as follows:

written in symbols will be as follows:

If C is an object class without parents then the linearization would look like this:

However, often it is not so simple, people often calculate the aggregation of lists according to the following rule:

This rule ensures that the unified operation preserves the order, if the order can be preserved. On the other hand, if the order cannot be preserved (as in the example above), then the consolidation cannot be calculated. The consolidation calculation is insignificant if C has only one parent (single inheritance); in this case:

However, in the case of multiple inheritance, things become more cumbersome and I don’t expect you to be able to understand the rule without a few examples.

For example :

Consider the following hierarchy:

In this case, the inheritance chart can be drawn as follows:

The inheritance tree of O, D, E and F is simple:

B’s inheritance tree is counted as

We see that D is a ‘good’ head, so we take it off the list and unite (O, EO, E). Now O is not a ‘good’ head, because it is in the tail of the EO chain. In this case, the rule says we have to skip the next string. Then we see that E is a ‘good’ head; we take it and we are shortened so that the union (O, O) gives O. So:

Similarly we find:

Now we can calculate:

It is done. Good luck.

Share the news now

Source : Viblo