8

How does a super method actually works in python?

In the given 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 on D, it output B->C instead of B->A (which I was expecting).

How is super inside B referring to an instance of C?

4
  • i guess mro in case of super method works differently. i think mro for super in B would be like [B,C,A,object] when called from D instance. Commented Apr 5, 2014 at 10:15
  • 1
    Raymond Hettinger's post super considered super is pretty much the definitive guide to this. Commented Apr 5, 2014 at 10:31
  • This is a case of diamond inheritance, what you "want" is ambiguous, whatever a given language does for you may surprise you. If you know Python MRO by heart you can settle for default. However for explicit is better than implicit, redefine test in D and call whichever base you want explicitly or better yet rewrite the method entirely. Python is duck-typed, you are trying to use classical typed inhretitance. ref: en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem Commented Apr 5, 2014 at 11:17
  • if this has been classical typed inheritance then this behaviour would not have resulted. see python-history.blogspot.in/2010/06/method-resolution-order.html for details. Commented Apr 5, 2014 at 11:21

2 Answers 2

2

From the docs:

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

Emphasis mine.

The MRO (as you have printed out) determines the method resolution order, which in this case is (D, B, C, A, object). So, super(B, self) when called within D returns a proxy object that will delegate methods to its sibling C, based on the MRO.

This can actually be used to extend behavior in inheritance hierarchies without modifying existing classes. Notice that B doesn't actually know which class its test() method is going to be dispatched to -- it simply uses an indirect super() call. You can insert a different class in the MRO by simply creating a new class that mixes multiple base classes in the required order.

For example, assume that your original hierarchy only contained classes A, B and D. Suppose, at a later time, you needed to instrument all of B's method calls with logging. Instead of modifying B you could simply create a new class C that does the logging and have D inherit C, thus inserting it in the MRO right after B.

Sign up to request clarification or add additional context in comments.

Comments

1

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

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

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

Hence if we redefine B as

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

then calling D().test() will output ==> 'B->A' explanation: from (1) above MRO of self == [D,B,C,A,object] from (2) above only those entries of MRO will be used which occur after provided class (ie C) hence super will call test method of A.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.