Brakke Baviaan
Brakke Baviaan

Reputation: 468

Implied parameters for super method in python

In a course about multiple-inheritance I came across this beautiful piece of code.

class First(object):
    def __init__(self):
        super(First, self).__init__()
        print("first")

class Second(object):
    def __init__(self):
        super(Second, self).__init__()
        print("second")

class Third(Second,First):
    def __init__(self):
        super(Third, self).__init__()
        print("third")

Third();

output:

first
second
third

I was a bit daunted so I started investigating why this stuff even works. I found a lovely article about this matter that explained some stuff about the mechanics behind super pretty well.

Then I started playing with the code and I found out that most of the code is actually redundant. I trimmed stuff step by step until only this poor skeleton remained.

class First():
    def __init__(self):
        super().__init__()
        print("first")

class Second():
    def __init__(self):
        super().__init__()
        print("second")

class Third(Second,First):
    def __init__(self):
        super().__init__()
        print("third")

Third();

This produces the exact same output. Now for object I understand that this can be left out, because all classes derive from the base class object. No problems there. However I don't quite understand what's behind the arguments that are passed to the super method. So I made this final adjustment to check if this would work as well:

class First():
    def __init__(self):
        super().__init__()
        print("first")

class Second():
    def __init__(self):
        super().__init__()
        print("second")

class Third(Second,First):
    def __init__(self):
        super(self).__init__()
        print("third")

Third();

output:

TypeError: super() argument 1 must be type, not Third

I can understand that self refers to Third in this case. In the case of super(Third,self), Third refers to a class which then would suffice as a type I suppose. So is it correct that when calling the super method, all of these redundant parts are always implied? Does anyone have some cool documentation about these mechanics other than the link I already found myself? It seems also that the order in which they are called is the reverse order in which the class arguments are listed. reversing into class Third(First,Second) gives output:

second
first
third

Some additional light on the matter would be much appreciated.

Upvotes: 0

Views: 514

Answers (2)

jsbueno
jsbueno

Reputation: 110311

When super was created, in the days of Python 2.x, the arguments to it (the class from which you wanted the "super" to, and the instance where you'd call the method) needed to be explicit.

From the language point of view, super was a common call with no special treatment.

On creating Python 3, people agreed that wanting to call the methods in the super-classes is common enough so to deserve special language treatment, and so it is: In Python 3, the call super got special enough that it is handled by the compiler itself (not the language runtime - the compiler, which runs, although in a transparent way, in a complete separated cycle from actually running the program). The compiler arranges for a hidden local variable to be created - it is called __class__, and for the parameterless super() call to actually be super(__class__, self). __class__ points to the class that is defined in the outer class statement body. This mechanism is actually one of the more "magic things happening under the hood" that takes place in the otherwise, super-explicit, Python.

The old, explicit, form of super(), with the parameters filled in, of course, still works.

One fine way to spot some of these "invisible" mechanisms in action is trying to place a parameterless super call inside an ordinary function, not a method: you will see an early-error when trying to run the code.

Upvotes: 1

Tim Roberts
Tim Roberts

Reputation: 54718

Your top example represents the first implementation of super. That implementation was made smarter in a later release, so the second example is the one you should use. The other is just outdated. If you are using multiple inheritance, you CAN pass the proper parent class to super, but that's a specialized situation.

Upvotes: 1

Related Questions