How does a super method work in python in case of multiple inheritance?

How does a super method really work in python?

In this code:

class A(object): def test(self): return 'A' class B(A): def test(self): return 'B->'+super(B, self).test() class C(A): def test(self): return 'C' class D(B,C): pass print B().test() # B->A print D().test() # B->C ???? # MRO of classes are as print 'mro of A', A.__mro__ # [A,object] print 'mro of B', B.__mro__ # [B,A,object] print 'mro of C', C.__mro__ # [C,A,object] print 'mro of D', D.__mro__ # [D,B,C,A,object] 

when test is called in D, it outputs B->C instead of B->A (which I expected).

How does super inside B refer to an instance of C?

+8
python inheritance oop multiple-inheritance method-resolution-order
source share
2 answers

In general, super () takes two arguments: a class and an instance of this class. (1) The instance (self) object determines which MRO will be used to resolve any attributes. (2) The provided class defines a subset of this MRO, because super () uses only those entries in the MRO that appear after the provided class.

Thus, in the above case, when the super inside B is called from an instance of D Object, self refers to the object D (i.e. the instance of the object) and mro D (i.e. the instance of the object) is [D, B, C, A ], therefore, according to k (2), only those entries in the MRO that occur after B. will be used. [C, A]

Thus, it is recommended to use a class in which super () was used as the first argument, and the standard self as the second argument. The resulting object will save the instance namespace dictionary self, but it only retrieves the attributes that were defined in the classes found later in the MRO than the provided class.

Therefore, if we redefine B as

 class B(A): def test(self): return 'B->'+super(C, self).test() 

then call D (). test () will output ==> 'B-> A' explanation: from (1) above MRO self == [D, B, C, A, object] from (2) above, only those MRO entries that occur after of the provided class (i.e. C) so super will call test method A.

+1
source share

From the docs:

super (type [, object-or-type]): Return a proxy object that delegates method calls to a parent or sibling type class

Emphasis on mine.

MRO (as you printed out) determines the resolution order of the method, which in this case (D, B, C, A, object). Thus, super(B, self) when called inside D returns a proxy object that will delegate methods to its affinity C based on MRO.

This can actually be used to extend behavior in inheritance hierarchies without changing existing classes. Note that B does not actually know which class its test() method will be sent to - it just uses the indirect call to super() . You can insert another class in the MRO by simply creating a new class that mixes several base classes in the desired order.

For example, suppose your original hierarchy contained only classes A , B and D Suppose in the future you needed to use all the calls of methods B with logging. Instead of modifying B you could simply create a new C class that does logging and has D inherit C by inserting it into the MRO right after B.

+2
source share

All Articles