Section 8.3. Not understanding the super() call


#1

I am struggling with the idea behind super() in Python. Typically, I should interpret it to be an invocation to a superclass. But, in the example below, the class QuotedMixin is at the very top of the inheritance hierarchy (except for the object class).

Thus my confusion. What exactly is happening with the line of code: super().row(quoted) at the bottom? Where does Python go to find the row() method? Perhaps super() is overloaded in Python to mean something completely different than the keyword super in other languages…?

This comes from section 8.3 Advanced Inheritance, and the github snippet.

class TableFormatter(object):
    def __init__(self, outfile=None):
        if outfile == None:
            outfile = sys.stdout
        self.outfile = outfile

    # Serves a design spec for making tables (use inheritance to customize)
    def headings(self, headers):
        raise NotImplementedError

    def row(self, rowdata):
        raise NotImplementedError
. . .
class QuotedMixin(object):
    def row(self, rowdata):
        quoted = [ '"{}"'.format(d) for d in rowdata ]
        super().row(quoted)

#2

I got it now. My problem was that my mind was firmly stuck in thinking in other languages. So I’m just going to document the issue here just in case others might come across it. Well, everything is covered very well in the docs, so I’m not going to repeat them here. (It was my bad! RFTM :blush:).

The crux of the biscuit is this statement from https://docs.python.org/3.6/library/functions.html#super:

This use case is unique to Python and is not found in statically compiled languages or languages that only support single inheritance.

… and there is more to read. Python official docs are excellent.

So perhaps my final comment is that the super() syntax and semantics should have been explained a bit in the video course presentation. This is a fundamentally crucial built-in function. And it is used frequently; so if not explained, it causes confusion.


#3

I can’t remember off the top of my head exactly what was said about super() in the video. However, like to think of inheritance as working in two different directions. There is an “upward” direction that reflects the Child->Parent relationship. However, there is also a “sideways” direction that reflects a Parent->Parent chain in multiple inheritance. So, if you have classes like this:

class Parent(object):
    def yow(self):
        print('Parent.yow')

class Mixin(object):
    def yow(self):
        print('Mixin.yow')
        super().yow()

class Child(Mixin, Parent):
    def yow(self):
        print('Child.yow')
        super().yow()

Python tries to arrange the classes so that all child classes are checked before their parent and so that multiple parents (in multiple inheritance) are checked in the order listed. Thus, in the above hierarchy for Child, there is a guarantee that Child will be checked before Parent, but there is also a guarantee that Mixin will be checked before Parent. Because of that, you can see some surprising results. For example, the super().yow() call in Mixin actually calls Parent.yow() even though this is not obvious from its implementation.

The precise ordering of classes can be found in the Child.__mro__ attribute. The algorithm for computing that order is something known as the C3 Linearization algorithm. The behavior of super() is to search for the next matching attribute by resuming the search with the next class on the MRO.

You should definitely look at the Raymond Hettinger article “Python’s super() considered super” for more information on this.

A point of curious history, the C3 algorithm upon which Python’s inheritance is based is from the Dylan programming language. In Dylan, there is an equivalent to super(), but it’s not called super()–it’s called next-method. Meaning go to the next method (on the MRO) whatever that might be–it’s not necessarily a direct parent.


#4

Thanks! This will definitely stick: The 2-step rule of (1) “upward” and then (2) “sideways” traversal. It makes a lot of sense to me now. Also the __mro__ attribute is something I will be checking into from now on when designing inheritance. Excellent stuff.

I do not know Dylan language, but the naming of next-method was indeed perfect. Appellation does matter a great deal in programming, and the meaning of super (as in ‘superclass’, or ‘supervisor’) typically connotes a vertical/hierarchical relationship. Hence the confusion of this Python newcomer.

But anyway, Python is a very pleasing language to learn. Your video course is one of the best I’ve ever taken… And BTW, anxiously and eagerly awaiting Python Essential Reference 5th edition book.

And I did re-visit your lesson ‘8.6 Advanced: How Inheritance Actually Works’. It is indeed all explained there. What cracked me up, at timestamp 5:08, you say:

“One final comment about this, the super function in Python is actually not well understood to be honest.”

And then you go on into lucid explanation of how the super function works. But I do love that quote. That made me feel so much better, knowing that I’m not a total dumbass, and you’ve seen other people having some problems with this as well. :sweat_smile: