How does Python's super() work with multiple inheritance?
I'm pretty much new in Python object oriented programming and I have trouble
understanding the super()
function (new style classes) especially when it comes to multiple inheritance.
For example if you have something like:
class First(object):
def __init__(self):
print "first"
class Second(object):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
What I don't get is: will the Third()
class inherit both constructor methods? If yes, then which one will be run with super() and why?
And what if you want to run the other one? I know it has something to do with Python method resolution order (MRO).
python multiple-inheritance
add a comment |
I'm pretty much new in Python object oriented programming and I have trouble
understanding the super()
function (new style classes) especially when it comes to multiple inheritance.
For example if you have something like:
class First(object):
def __init__(self):
print "first"
class Second(object):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
What I don't get is: will the Third()
class inherit both constructor methods? If yes, then which one will be run with super() and why?
And what if you want to run the other one? I know it has something to do with Python method resolution order (MRO).
python multiple-inheritance
In fact, multiple inheritance is the only case wheresuper()
is of any use. I would not recommend using it with classes using linear inheritance, where it's just useless overhead.
– Bachsau
Apr 15 '18 at 21:56
@Bachsau is technically correct in that it is a small overhead but super() is more pythonic and allows for re-factoring and changes to the code over time. Use super() unless you really need a named class specific method.
– Paul Whipp
Nov 18 '18 at 19:55
1
Another problem withsuper()
is, that it forces every subclass to use it as well, while when not usingsuper()
, everyone subclassing it can decide himself. If a developer using it doesn't know aboutsuper()
or doesn't know it was used, problems with the mro can arise that are very hard to track down.
– Bachsau
Nov 30 '18 at 13:37
add a comment |
I'm pretty much new in Python object oriented programming and I have trouble
understanding the super()
function (new style classes) especially when it comes to multiple inheritance.
For example if you have something like:
class First(object):
def __init__(self):
print "first"
class Second(object):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
What I don't get is: will the Third()
class inherit both constructor methods? If yes, then which one will be run with super() and why?
And what if you want to run the other one? I know it has something to do with Python method resolution order (MRO).
python multiple-inheritance
I'm pretty much new in Python object oriented programming and I have trouble
understanding the super()
function (new style classes) especially when it comes to multiple inheritance.
For example if you have something like:
class First(object):
def __init__(self):
print "first"
class Second(object):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
What I don't get is: will the Third()
class inherit both constructor methods? If yes, then which one will be run with super() and why?
And what if you want to run the other one? I know it has something to do with Python method resolution order (MRO).
python multiple-inheritance
python multiple-inheritance
edited Jul 29 '14 at 20:39
Peter O.
20.7k95969
20.7k95969
asked Jul 18 '10 at 21:40
CallistoCallisto
3,3813114
3,3813114
In fact, multiple inheritance is the only case wheresuper()
is of any use. I would not recommend using it with classes using linear inheritance, where it's just useless overhead.
– Bachsau
Apr 15 '18 at 21:56
@Bachsau is technically correct in that it is a small overhead but super() is more pythonic and allows for re-factoring and changes to the code over time. Use super() unless you really need a named class specific method.
– Paul Whipp
Nov 18 '18 at 19:55
1
Another problem withsuper()
is, that it forces every subclass to use it as well, while when not usingsuper()
, everyone subclassing it can decide himself. If a developer using it doesn't know aboutsuper()
or doesn't know it was used, problems with the mro can arise that are very hard to track down.
– Bachsau
Nov 30 '18 at 13:37
add a comment |
In fact, multiple inheritance is the only case wheresuper()
is of any use. I would not recommend using it with classes using linear inheritance, where it's just useless overhead.
– Bachsau
Apr 15 '18 at 21:56
@Bachsau is technically correct in that it is a small overhead but super() is more pythonic and allows for re-factoring and changes to the code over time. Use super() unless you really need a named class specific method.
– Paul Whipp
Nov 18 '18 at 19:55
1
Another problem withsuper()
is, that it forces every subclass to use it as well, while when not usingsuper()
, everyone subclassing it can decide himself. If a developer using it doesn't know aboutsuper()
or doesn't know it was used, problems with the mro can arise that are very hard to track down.
– Bachsau
Nov 30 '18 at 13:37
In fact, multiple inheritance is the only case where
super()
is of any use. I would not recommend using it with classes using linear inheritance, where it's just useless overhead.– Bachsau
Apr 15 '18 at 21:56
In fact, multiple inheritance is the only case where
super()
is of any use. I would not recommend using it with classes using linear inheritance, where it's just useless overhead.– Bachsau
Apr 15 '18 at 21:56
@Bachsau is technically correct in that it is a small overhead but super() is more pythonic and allows for re-factoring and changes to the code over time. Use super() unless you really need a named class specific method.
– Paul Whipp
Nov 18 '18 at 19:55
@Bachsau is technically correct in that it is a small overhead but super() is more pythonic and allows for re-factoring and changes to the code over time. Use super() unless you really need a named class specific method.
– Paul Whipp
Nov 18 '18 at 19:55
1
1
Another problem with
super()
is, that it forces every subclass to use it as well, while when not using super()
, everyone subclassing it can decide himself. If a developer using it doesn't know about super()
or doesn't know it was used, problems with the mro can arise that are very hard to track down.– Bachsau
Nov 30 '18 at 13:37
Another problem with
super()
is, that it forces every subclass to use it as well, while when not using super()
, everyone subclassing it can decide himself. If a developer using it doesn't know about super()
or doesn't know it was used, problems with the mro can arise that are very hard to track down.– Bachsau
Nov 30 '18 at 13:37
add a comment |
12 Answers
12
active
oldest
votes
This is detailed with a reasonable amount of detail by Guido himself in his blog post Method Resolution Order (including two earlier attempts).
In your example, Third()
will call First.__init__
. Python looks for each attribute in the class's parents as they are listed left to right. In this case we are looking for __init__
. So, if you define
class Third(First, Second):
...
Python will start by looking at First
, and, if First
doesn't have the attribute, then it will look at Second
.
This situation becomes more complex when inheritance starts crossing paths (for example if First
inherited from Second
). Read the link above for more details, but, in a nutshell, Python will try to maintain the order in which each class appears on the inheritance list, starting with the child class itself.
So, for instance, if you had:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
the MRO would be [Fourth, Second, Third, First].
By the way: if Python cannot find a coherent method resolution order, it'll raise an exception, instead of falling back to a behaviour which might surprise the user.
Edited to add example of an ambiguous MRO:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Should Third
's MRO be [First, Second]
or [Second, First]
? There's no obvious expectation, and Python will raise an error:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Edit: I see several people arguing that the examples above lack super()
calls, so let me explain: The point of the examples is to show how the MRO is constructed. They are not intended to print "firstnsecondthird" or whatever. You can – and should, of course, play around with the example, add super()
calls, see what happens, and gain a deeper understanding of Python's inheritance model. But my goal here is to keep it simple and show how the MRO is built. And it is built as I explained:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
8
It becomes more interesting (and, arguably, more confusing) when you start calling super() in First, Second, and Third [ pastebin.com/ezTyZ5Wa ].
– gatoatigrado
Jul 10 '12 at 0:37
38
I think the lack of super calls in the first classes is a really big problem with this answer; without discussing how/why thats important critical understanding to the question is lost.
– Sam Hartman
Dec 7 '13 at 20:14
3
This answer is simply wrong. Without super() calls in the parents, nothing will happen. @lifeless's answer is the correct one.
– Cerin
Oct 17 '15 at 1:01
4
@Cerin The point of this example is to show how the MRO is constructed. The example is NOT intended to print "firstnsecondthird" or whatever. And the MRO is indeed correct: Fourth.__mro__ == (<class 'main.Fourth'>, <class 'main.Second'>, <class 'main.Third'>, <class 'main.First'>, <type 'object'>)
– rbp
Oct 17 '15 at 10:30
1
@gatoatigrado is right when he says it gets more confusing. I followed his logic to try understading MRO and super in depth. Here is what I learned. Now it is clear to me that, in this case, Second.super will call Third, although Third is not inherited by Second.
– pedrovgp
Jan 31 '17 at 12:26
|
show 8 more comments
Your code, and the other answers, are all buggy. They are missing the super()
calls in the first two classes that are required for co-operative subclassing to work.
Here is a fixed version of the 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print("third")
The super()
call finds the next method in the MRO at each step, which is why First and Second have to have it too, otherwise execution stops at the end of Second.__init__()
.
This is what I get:
>>> Third()
second
first
third
51
What to do if these classes need different parameters to initialize themselves?
– calfzhou
May 8 '14 at 9:23
2
"co-operative subclassing"
– Quant Metropolis
Sep 5 '14 at 11:13
2
In this way the init methods of BOTH base classes will get executed, while the original example calls only the first init encountered in the MRO. I guess that is implied by the term "co-operative subclassing", but a clarification would have been useful ('Explicit is better than implicit', you know ;) )
– Quant Metropolis
Sep 5 '14 at 11:19
1
Yes, if you are passing different parameters to a method being called via super, all the implementations of that method going up the MRO towards object() need to have compatible signatures. This can be achieved through keyword parameters: accept more parameters than the method uses, and ignore extra ones. Its generally considered ugly to do this, and for most cases adding new methods is better, but init is (nearly?) unique as a special method name but with user defined parameters.
– lifeless
Dec 1 '14 at 10:15
7
The design of multiple inheritance is really really bad in python. The base classes almost need to know who is going to derive it, and how many other base classes the derived will derive, and in what order... otherwisesuper
will either fail to run (because of parameter mismatch), or it will not call few of the bases (because you didn't writesuper
in one of the base which breaks the link)!
– Nawaz
Nov 9 '16 at 13:12
|
show 2 more comments
I wanted to elaborate the answer by lifeless a bit because when I started reading about how to use super() in a multiple inheritance hierarchy in Python, I did't get it immediately.
What you need to understand is that super(MyClass, self).__init__()
provides the next __init__
method according to the used Method Resolution Ordering (MRO) algorithm in the context of the complete inheritance hierarchy.
This last part is crucial to understand. Let's consider the example again:
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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
According to this article about Method Resolution Order by Guido van Rossum, the order to resolve __init__
is calculated (before Python 2.3) using a "depth-first left-to-right traversal" :
Third --> First --> object --> Second --> object
After removing all duplicates, except for the last one, we get :
Third --> First --> Second --> object
So, lets follow what happens when we instantiate an instance of the Third
class, e.g. x = Third()
.
According to MRO
__init__
of Third is called first.Next, according to the MRO, inside the
__init__
methodsuper(Third,
resolves to the
self).__init__()__init__
method of First, which
gets called.Inside
__init__
of Firstsuper(First, self).__init__()
calls the__init__
of Second, because that is what the MRO dictates!Inside
__init__
of Secondsuper(Second, self).__init__()
calls
the__init__
of object, which amounts to nothing. After that
"second" is printed.After
super(First, self).__init__()
completed,
"first" is printed.After
super(Third, self).__init__()
completed, "that's it" is printed.
This details out why instantiating Third() results in to :
>>> x = Third()
second
first
that's it
The MRO algorithm has been improved from Python 2.3 onwards to work well in complex cases, but I guess that using the "depth-first left-to-right traversal" + "removing duplicates expect for the last" still works in most cases (please comment if this is not the case). Be sure to read the blog post by Guido!
3
I still do not understand why: Inside init of First super(First, self).__init__() calls the init of Second, because that is what the MRO dictates!
– user389955
Sep 20 '17 at 19:52
@user389955 The object created is of type Third which has all init methods. So if you assume MRO creates a list of all init functions in a specific order, with every super call, you are going one step forward till you reach the end.
– Sreekumar R
Jan 13 '18 at 18:10
9
I think Step 3 needs more explanation: IfThird
did not inherit fromSecond
, thensuper(First, self).__init__
would callobject.__init__
and after returning, "first" would be printed. But becauseThird
inherits from bothFirst
andSecond
, rather than callingobject.__init__
afterFirst.__init__
the MRO dictates that only the final call toobject.__init__
is preserved, and the print statements inFirst
andSecond
are not reached untilobject.__init__
returns. SinceSecond
was the last to callobject.__init__
, it returns insideSecond
before returning inFirst
.
– MountainDrew
Feb 14 '18 at 16:45
2
You nailed it, very good explanation! Kodos!
– Ghasan
Feb 19 '18 at 9:45
Interestingly, PyCharm seems to know all this (its hints talk about which parameters go with which calls to super. It also has some notion of covariance of inputs, so it recognizesList[subclass]
as aList[superclass]
ifsubclass
is a subclass ofsuperclass
(List
comes from thetyping
module of PEP 483 iirc).
– Reb.Cabin
May 9 '18 at 1:58
add a comment |
This is known as the Diamond Problem, the page has an entry on Python, but in short, Python will call the superclass's methods from left to right.
This is not the Diamond Problem. The Diamond Problem involves four classes and the OP's question only involves three.
– Ian Goodfellow
Aug 6 '11 at 16:14
121
object
is the fourth
– GP89
Oct 26 '11 at 13:30
add a comment |
This is to how I solved to issue of having multiple inheritance with different variables for initialization and having multiple MixIns with the same function call. I had to explicitly add variables to passed **kwargs and add a MixIn interface to be an endpoint for super calls.
Here A
is an extendable base class and B
and C
are MixIn classes both who provide function f
. A
and B
both expect parameter v
in their __init__
and C
expects w
.
The function f
takes one parameter y
. Q
inherits from all three classes. MixInF
is the mixin interface for B
and C
.
- IPython NoteBook Of This Code
- Github Repo with code example
class A(object):
def __init__(self, v, *args, **kwargs):
print "A:init:v[{0}]".format(v)
kwargs['v']=v
super(A, self).__init__(*args, **kwargs)
self.v = v
class MixInF(object):
def __init__(self, *args, **kwargs):
print "IObject:init"
def f(self, y):
print "IObject:y[{0}]".format(y)
class B(MixInF):
def __init__(self, v, *args, **kwargs):
print "B:init:v[{0}]".format(v)
kwargs['v']=v
super(B, self).__init__(*args, **kwargs)
self.v = v
def f(self, y):
print "B:f:v[{0}]:y[{1}]".format(self.v, y)
super(B, self).f(y)
class C(MixInF):
def __init__(self, w, *args, **kwargs):
print "C:init:w[{0}]".format(w)
kwargs['w']=w
super(C, self).__init__(*args, **kwargs)
self.w = w
def f(self, y):
print "C:f:w[{0}]:y[{1}]".format(self.w, y)
super(C, self).f(y)
class Q(C,B,A):
def __init__(self, v, w):
super(Q, self).__init__(v=v, w=w)
def f(self, y):
print "Q:f:y[{0}]".format(y)
super(Q, self).f(y)
I think this should perhaps be a separate question-and-answer, as the MRO is a large enough topic on its own without getting into dealing with varying arguments across functions with inheritance (multiple inheritance is a special case of that).
– lifeless
Dec 1 '14 at 10:21
6
Theoretically, yes. Practically, this scenario has come up every time I've encountered Diamond inheritance in python, so I added it here. Since, this is where I go every time I cannot cleanly avoid diamond inheritance. Here are some extra links for future me: rhettinger.wordpress.com/2011/05/26/super-considered-super code.activestate.com/recipes/…
– brent.payne
Dec 3 '14 at 20:40
What we want is programs with semantically meaningful parameter names. But in this example almost all the parameters are anonymously named, which will make it much more difficult for the original programmer to document the code and for another programmer to read the code.
– Arthur
Nov 29 '16 at 13:55
A pull request to the github repo with descriptive names would be appreciated
– brent.payne
Nov 29 '16 at 20:41
@brent.payne I think @Arthur meant that your whole approach relies on usingargs
/kwargs
rather than named parameters.
– max
Jun 11 '17 at 23:00
|
show 1 more comment
I understand this doesn't directly answer the super()
question, but I feel it's relevant enough to share.
There is also a way to directly call each inherited class:
class First(object):
def __init__(self):
print '1'
class Second(object):
def __init__(self):
print '2'
class Third(First, Second):
def __init__(self):
Second.__init__(self)
Just note that if you do it this way, you'll have to call each manually as I'm pretty sure First
's __init__()
won't be called.
3
It won't be called because you did not call each inherited class. The problem is rather that ifFirst
andSecond
are both inheriting another class and calling it directly then this common class (starting point of the diamond) is called twice. super is avoiding this.
– Trilarion
Jul 29 '14 at 12:04
@Trilarion Yea, I was confident it wouldn't. However, I didn't definitively know and I didn't want to state as if I did even though it was very unlikely. That's a good point about theobject
being called twice. I didn't think about that. I just wanted to make the point that you call parent classes directly.
– Seaux
Jul 30 '14 at 18:58
Unfortunately, this breaks if init tries to access any private methods :(
– Erik Aronesty
May 10 '18 at 21:29
add a comment |
About @calfzhou's comment, you can use, as usually, **kwargs
:
Online running example
class A(object):
def __init__(self, a, *args, **kwargs):
print("A", a)
class B(A):
def __init__(self, b, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
print("B", b)
class A1(A):
def __init__(self, a1, *args, **kwargs):
super(A1, self).__init__(*args, **kwargs)
print("A1", a1)
class B1(A1, B):
def __init__(self, b1, *args, **kwargs):
super(B1, self).__init__(*args, **kwargs)
print("B1", b1)
B1(a1=6, b1=5, b="hello", a=None)
Result:
A None
B hello
A1 6
B1 5
You can also use them positionally:
B1(5, 6, b="hello", a=None)
but you have to remember the MRO, it's really confusing.
I can be a little annoying, but I noticed that people forgot every time to use *args
and **kwargs
when they override a method, while it's one of few really useful and sane use of these 'magic variables'.
Wow that's really ugly. It's a shame you can't just say which specific superclass you want to call. Still, this gives me even more incentive to use composition and avoid multiple inheritance like the plague.
– Tom Busby
Feb 6 '17 at 15:55
add a comment |
Overall
Assuming everything descends from object
(you are on your own if it doesn't), Python computes a method resolution order (MRO) based on your class inheritance tree. The MRO satisfies 3 properties:
- Children of a class come before their parents
- Left parents come before right parents
- A class only appears once in the MRO
If no such ordering exists, Python errors. The inner workings of this is a C3 Linerization of the classes ancestry. Read all about it here: https://www.python.org/download/releases/2.3/mro/
Thus, in both of the examples below, it is:
- Child
- Left
- Right
- Parent
When a method is called, the first occurrence of that method in the MRO is the one that is called. Any class that doesn't implement that method is skipped. Any call to super
within that method will call the next occurrence of that method in the MRO. Consequently, it matters both what order you place classes in inheritance, and where you put the calls to super
in the methods.
With super
first in each method
class Parent(object):
def __init__(self):
super(Parent, self).__init__()
print "parent"
class Left(Parent):
def __init__(self):
super(Left, self).__init__()
print "left"
class Right(Parent):
def __init__(self):
super(Right, self).__init__()
print "right"
class Child(Left, Right):
def __init__(self):
super(Child, self).__init__()
print "child"
Child()
Outputs:
parent
right
left
child
With super
last in each method
class Parent(object):
def __init__(self):
print "parent"
super(Parent, self).__init__()
class Left(Parent):
def __init__(self):
print "left"
super(Left, self).__init__()
class Right(Parent):
def __init__(self):
print "right"
super(Right, self).__init__()
class Child(Left, Right):
def __init__(self):
print "child"
super(Child, self).__init__()
Child()
Outputs:
child
left
right
parent
I see that you can accessLeft
usingsuper()
fromChild
. suppose I want to accessRight
from insideChild
. Is there a way to accessRight
fromChild
using super? Or should I directly calledRight
from insidesuper
?
– alpha_989
Apr 15 '18 at 22:21
3
@alpha_989 If you want to access the method of a particular class only, you should reference that class directly rather than using super. Super is about following the chain of inheritance, not getting to a specific class's method.
– Zags
May 6 '18 at 12:04
Thanks for explicitly mentioning 'A class only appears once in the MRO'. This solved my problem. Now I finally understand how multiple inheritance works. Somebody needed to mention the properties of MRO!
– Tushar Vazirani
Nov 19 '18 at 20:25
add a comment |
Another not yet covered point is passing parameters for initialization of classes. Since the destination of super
depends on the subclass the only good way to pass parameters is packing them all together. Then be careful to not have the same parameter name with different meanings.
Example:
class A(object):
def __init__(self, **kwargs):
print('A.__init__')
super().__init__()
class B(A):
def __init__(self, **kwargs):
print('B.__init__ {}'.format(kwargs['x']))
super().__init__(**kwargs)
class C(A):
def __init__(self, **kwargs):
print('C.__init__ with {}, {}'.format(kwargs['a'], kwargs['b']))
super().__init__(**kwargs)
class D(B, C): # MRO=D, B, C, A
def __init__(self):
print('D.__init__')
super().__init__(a=1, b=2, x=3)
print(D.mro())
D()
gives:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D.__init__
B.__init__ 3
C.__init__ with 1, 2
A.__init__
Calling the super class __init__
directly to more direct assignment of parameters is tempting but fails if there is any super
call in a super class and/or the MRO is changed and class A may be called multiple times, depending on the implementation.
To conclude: cooperative inheritance and super and specific parameters for initialization aren't working together very well.
add a comment |
class First(object):
def __init__(self, a):
print "first", a
super(First, self).__init__(20)
class Second(object):
def __init__(self, a):
print "second", a
super(Second, self).__init__()
class Third(First, Second):
def __init__(self):
super(Third, self).__init__(10)
print "that's it"
t = Third()
Output is
first 10
second 20
that's it
Call to Third() locates the init defined in Third. And call to super in that routine invokes init defined in First. MRO=[First, Second].
Now call to super in init defined in First will continue searching MRO and find init defined in Second, and any call to super will hit the default object init. I hope this example clarifies the concept.
If you don't call super from First. The chain stops and you will get the following output.
first 10
that's it
1
that's because in class First, you called 'print' first then 'super'.
– rocky qi
Feb 25 '16 at 2:00
2
that was to illustrate the calling order
– Seraj Ahmad
Mar 6 '16 at 8:34
add a comment |
I would like to add to what @Visionscaper says at the top:
Third --> First --> object --> Second --> object
In this case the interpreter doesnt filter out the object class because its duplicated, rather its because Second appears in a head position and doesnt appear in the tail position in a hierarchy subset. While object only appears in tail positions and is not considered a strong position in C3 algorithm to determine priority.
The linearisation(mro) of a class C, L(C), is the
- the Class C
- plus the merge of
- linearisation of its parents P1, P2, .. = L(P1, P2, ...) and
- the list of its parents P1, P2, ..
Linearised Merge is done by selecting the common classes that appears as the head of lists and not the tail since order matters(will become clear below)
The linearisation of Third can be computed as follows:
L(O) := [O] // the linearization(mro) of O(object), because O has no parents
L(First) := [First] + merge(L(O), [O])
= [First] + merge([O], [O])
= [First, O]
// Similarly,
L(Second) := [Second, O]
L(Third) := [Third] + merge(L(First), L(Second), [First, Second])
= [Third] + merge([First, O], [Second, O], [First, Second])
// class First is a good candidate for the first merge step, because it only appears as the head of the first and last lists
// class O is not a good candidate for the next merge step, because it also appears in the tails of list 1 and 2,
= [Third, First] + merge([O], [Second, O], [Second])
// class Second is a good candidate for the second merge step, because it appears as the head of the list 2 and 3
= [Third, First, Second] + merge([O], [O])
= [Third, First, Second, O]
Thus for a super() implementation in the following 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
it becomes obvious how this method will be resolved
Third.__init__() ---> First.__init__() ---> Second.__init__() --->
Object.__init__() ---> returns ---> Second.__init__() -
prints "second" - returns ---> First.__init__() -
prints "first" - returns ---> Third.__init__() - prints "that's it"
"rather its because Second appears in a head position and doesn't appear in the tail position in a hierarchy subset." It's not clear what a head or tail position is, nor what a hierarchy subset is or which subset you are referring to.
– OrangeSherbet
Jul 18 '17 at 21:37
Tail position refers to classes that are higher in the class hierarchy and vice versa. The base class 'object' is at the end of the tail. The key to understanding the mro algorithm is how 'Second' appears as the super of 'First'. We would normally assume it to be the 'object' class. Thats true, but, only in the perspective of the 'First' class. However when viewed from the 'Third' class perspective, the hierarchy order for 'First' is different and is calculated as shown above. mro algorithm tries to create this perspective(or hierarchy subset) for all multiple inherited classes
– supi
Jul 22 '17 at 13:05
add a comment |
In learningpythonthehardway I learn something called super() an in-built function if not mistaken. Calling super() function can help the inheritance to pass through the parent and 'siblings' and help you to see clearer. I am still a beginner but I love to share my experience on using this super() in python2.7.
If you have read through the comments in this page, you will heard of Method Resolution Order (MRO), method being the function you wrote, MRO will be using Depth-First-Left-to-Right scheme to search and run. You can do more research on that.
By adding super() function
super(First, self).__init__() #example for class First.
You can connect multiple instances and 'families' with super(), by adding in each and every one in them. And it will execute the methods, go through them and make sure you didn't miss out! However adding them before or after does make difference you will know if you have done the learningpythonthehardway exercise 44. Let the fun begins!!
Taking example below, you can copy & paste and try run it:
class First(object):
def __init__(self):
print("first")
class Second(First):
def __init__(self):
print("second (before)")
super(Second, self).__init__()
print("second (after)")
class Third(First):
def __init__(self):
print("third (before)")
super(Third, self).__init__()
print("third (after)")
class Fourth(First):
def __init__(self):
print("fourth (before)")
super(Fourth, self).__init__()
print("fourth (after)")
class Fifth(Second, Third, Fourth):
def __init__(self):
print("fifth (before)")
super(Fifth, self).__init__()
print("fifth (after)")
Fifth()
How does it run? Instance of fifth() will goes like this. Each steps goes from class to class where the super function added.
1.) print("fifth (before)")
2.) super()>[Second, Third, Fourth] (Left to right)
3.) print("second (before)")
4.) super()> First (First is the Parent which inherit from object)
Parent was found and it will goes continue to Third and Fourth!!
5.) print("third (before)")
6.) super()> First (Parent class)
7.) print ("Fourth (before)")
8.) super()> First (Parent class)
Now all the classes with super() has been accessed! The parent class has been found and executed and now it continues to un-box the function in the inheritances to finished the codes.
9.) print("first") (Parent)
10.) print ("Fourth (after)") (Class Fourth un-box)
11.) print("third (after)") (Class Third un-box)
12.) print("second (after)") (Class Second un-box)
13.) print("fifth (after)") (Class Fifth un-box)
14.) Fifth() executed
The outcome of the program above:
fifth (before)
second (before
third (before)
fourth (before)
first
fourth (after)
third (after)
second (after)
fifth (after)
For me by adding super() allows me to see clearer on how python would execute my coding and make sure the inheritance can access the method I intended.
Thanks for the detailed demo!
– Tushar Vazirani
Nov 19 '18 at 20:29
add a comment |
protected by Community♦ Dec 9 '16 at 17:53
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
12 Answers
12
active
oldest
votes
12 Answers
12
active
oldest
votes
active
oldest
votes
active
oldest
votes
This is detailed with a reasonable amount of detail by Guido himself in his blog post Method Resolution Order (including two earlier attempts).
In your example, Third()
will call First.__init__
. Python looks for each attribute in the class's parents as they are listed left to right. In this case we are looking for __init__
. So, if you define
class Third(First, Second):
...
Python will start by looking at First
, and, if First
doesn't have the attribute, then it will look at Second
.
This situation becomes more complex when inheritance starts crossing paths (for example if First
inherited from Second
). Read the link above for more details, but, in a nutshell, Python will try to maintain the order in which each class appears on the inheritance list, starting with the child class itself.
So, for instance, if you had:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
the MRO would be [Fourth, Second, Third, First].
By the way: if Python cannot find a coherent method resolution order, it'll raise an exception, instead of falling back to a behaviour which might surprise the user.
Edited to add example of an ambiguous MRO:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Should Third
's MRO be [First, Second]
or [Second, First]
? There's no obvious expectation, and Python will raise an error:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Edit: I see several people arguing that the examples above lack super()
calls, so let me explain: The point of the examples is to show how the MRO is constructed. They are not intended to print "firstnsecondthird" or whatever. You can – and should, of course, play around with the example, add super()
calls, see what happens, and gain a deeper understanding of Python's inheritance model. But my goal here is to keep it simple and show how the MRO is built. And it is built as I explained:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
8
It becomes more interesting (and, arguably, more confusing) when you start calling super() in First, Second, and Third [ pastebin.com/ezTyZ5Wa ].
– gatoatigrado
Jul 10 '12 at 0:37
38
I think the lack of super calls in the first classes is a really big problem with this answer; without discussing how/why thats important critical understanding to the question is lost.
– Sam Hartman
Dec 7 '13 at 20:14
3
This answer is simply wrong. Without super() calls in the parents, nothing will happen. @lifeless's answer is the correct one.
– Cerin
Oct 17 '15 at 1:01
4
@Cerin The point of this example is to show how the MRO is constructed. The example is NOT intended to print "firstnsecondthird" or whatever. And the MRO is indeed correct: Fourth.__mro__ == (<class 'main.Fourth'>, <class 'main.Second'>, <class 'main.Third'>, <class 'main.First'>, <type 'object'>)
– rbp
Oct 17 '15 at 10:30
1
@gatoatigrado is right when he says it gets more confusing. I followed his logic to try understading MRO and super in depth. Here is what I learned. Now it is clear to me that, in this case, Second.super will call Third, although Third is not inherited by Second.
– pedrovgp
Jan 31 '17 at 12:26
|
show 8 more comments
This is detailed with a reasonable amount of detail by Guido himself in his blog post Method Resolution Order (including two earlier attempts).
In your example, Third()
will call First.__init__
. Python looks for each attribute in the class's parents as they are listed left to right. In this case we are looking for __init__
. So, if you define
class Third(First, Second):
...
Python will start by looking at First
, and, if First
doesn't have the attribute, then it will look at Second
.
This situation becomes more complex when inheritance starts crossing paths (for example if First
inherited from Second
). Read the link above for more details, but, in a nutshell, Python will try to maintain the order in which each class appears on the inheritance list, starting with the child class itself.
So, for instance, if you had:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
the MRO would be [Fourth, Second, Third, First].
By the way: if Python cannot find a coherent method resolution order, it'll raise an exception, instead of falling back to a behaviour which might surprise the user.
Edited to add example of an ambiguous MRO:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Should Third
's MRO be [First, Second]
or [Second, First]
? There's no obvious expectation, and Python will raise an error:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Edit: I see several people arguing that the examples above lack super()
calls, so let me explain: The point of the examples is to show how the MRO is constructed. They are not intended to print "firstnsecondthird" or whatever. You can – and should, of course, play around with the example, add super()
calls, see what happens, and gain a deeper understanding of Python's inheritance model. But my goal here is to keep it simple and show how the MRO is built. And it is built as I explained:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
8
It becomes more interesting (and, arguably, more confusing) when you start calling super() in First, Second, and Third [ pastebin.com/ezTyZ5Wa ].
– gatoatigrado
Jul 10 '12 at 0:37
38
I think the lack of super calls in the first classes is a really big problem with this answer; without discussing how/why thats important critical understanding to the question is lost.
– Sam Hartman
Dec 7 '13 at 20:14
3
This answer is simply wrong. Without super() calls in the parents, nothing will happen. @lifeless's answer is the correct one.
– Cerin
Oct 17 '15 at 1:01
4
@Cerin The point of this example is to show how the MRO is constructed. The example is NOT intended to print "firstnsecondthird" or whatever. And the MRO is indeed correct: Fourth.__mro__ == (<class 'main.Fourth'>, <class 'main.Second'>, <class 'main.Third'>, <class 'main.First'>, <type 'object'>)
– rbp
Oct 17 '15 at 10:30
1
@gatoatigrado is right when he says it gets more confusing. I followed his logic to try understading MRO and super in depth. Here is what I learned. Now it is clear to me that, in this case, Second.super will call Third, although Third is not inherited by Second.
– pedrovgp
Jan 31 '17 at 12:26
|
show 8 more comments
This is detailed with a reasonable amount of detail by Guido himself in his blog post Method Resolution Order (including two earlier attempts).
In your example, Third()
will call First.__init__
. Python looks for each attribute in the class's parents as they are listed left to right. In this case we are looking for __init__
. So, if you define
class Third(First, Second):
...
Python will start by looking at First
, and, if First
doesn't have the attribute, then it will look at Second
.
This situation becomes more complex when inheritance starts crossing paths (for example if First
inherited from Second
). Read the link above for more details, but, in a nutshell, Python will try to maintain the order in which each class appears on the inheritance list, starting with the child class itself.
So, for instance, if you had:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
the MRO would be [Fourth, Second, Third, First].
By the way: if Python cannot find a coherent method resolution order, it'll raise an exception, instead of falling back to a behaviour which might surprise the user.
Edited to add example of an ambiguous MRO:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Should Third
's MRO be [First, Second]
or [Second, First]
? There's no obvious expectation, and Python will raise an error:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Edit: I see several people arguing that the examples above lack super()
calls, so let me explain: The point of the examples is to show how the MRO is constructed. They are not intended to print "firstnsecondthird" or whatever. You can – and should, of course, play around with the example, add super()
calls, see what happens, and gain a deeper understanding of Python's inheritance model. But my goal here is to keep it simple and show how the MRO is built. And it is built as I explained:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
This is detailed with a reasonable amount of detail by Guido himself in his blog post Method Resolution Order (including two earlier attempts).
In your example, Third()
will call First.__init__
. Python looks for each attribute in the class's parents as they are listed left to right. In this case we are looking for __init__
. So, if you define
class Third(First, Second):
...
Python will start by looking at First
, and, if First
doesn't have the attribute, then it will look at Second
.
This situation becomes more complex when inheritance starts crossing paths (for example if First
inherited from Second
). Read the link above for more details, but, in a nutshell, Python will try to maintain the order in which each class appears on the inheritance list, starting with the child class itself.
So, for instance, if you had:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First):
def __init__(self):
print "third"
class Fourth(Second, Third):
def __init__(self):
super(Fourth, self).__init__()
print "that's it"
the MRO would be [Fourth, Second, Third, First].
By the way: if Python cannot find a coherent method resolution order, it'll raise an exception, instead of falling back to a behaviour which might surprise the user.
Edited to add example of an ambiguous MRO:
class First(object):
def __init__(self):
print "first"
class Second(First):
def __init__(self):
print "second"
class Third(First, Second):
def __init__(self):
print "third"
Should Third
's MRO be [First, Second]
or [Second, First]
? There's no obvious expectation, and Python will raise an error:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution order (MRO) for bases Second, First
Edit: I see several people arguing that the examples above lack super()
calls, so let me explain: The point of the examples is to show how the MRO is constructed. They are not intended to print "firstnsecondthird" or whatever. You can – and should, of course, play around with the example, add super()
calls, see what happens, and gain a deeper understanding of Python's inheritance model. But my goal here is to keep it simple and show how the MRO is built. And it is built as I explained:
>>> Fourth.__mro__
(<class '__main__.Fourth'>,
<class '__main__.Second'>, <class '__main__.Third'>,
<class '__main__.First'>,
<type 'object'>)
edited Nov 14 '17 at 7:21
akaihola
20.1k54657
20.1k54657
answered Jul 18 '10 at 21:52
rbprbp
28.8k32825
28.8k32825
8
It becomes more interesting (and, arguably, more confusing) when you start calling super() in First, Second, and Third [ pastebin.com/ezTyZ5Wa ].
– gatoatigrado
Jul 10 '12 at 0:37
38
I think the lack of super calls in the first classes is a really big problem with this answer; without discussing how/why thats important critical understanding to the question is lost.
– Sam Hartman
Dec 7 '13 at 20:14
3
This answer is simply wrong. Without super() calls in the parents, nothing will happen. @lifeless's answer is the correct one.
– Cerin
Oct 17 '15 at 1:01
4
@Cerin The point of this example is to show how the MRO is constructed. The example is NOT intended to print "firstnsecondthird" or whatever. And the MRO is indeed correct: Fourth.__mro__ == (<class 'main.Fourth'>, <class 'main.Second'>, <class 'main.Third'>, <class 'main.First'>, <type 'object'>)
– rbp
Oct 17 '15 at 10:30
1
@gatoatigrado is right when he says it gets more confusing. I followed his logic to try understading MRO and super in depth. Here is what I learned. Now it is clear to me that, in this case, Second.super will call Third, although Third is not inherited by Second.
– pedrovgp
Jan 31 '17 at 12:26
|
show 8 more comments
8
It becomes more interesting (and, arguably, more confusing) when you start calling super() in First, Second, and Third [ pastebin.com/ezTyZ5Wa ].
– gatoatigrado
Jul 10 '12 at 0:37
38
I think the lack of super calls in the first classes is a really big problem with this answer; without discussing how/why thats important critical understanding to the question is lost.
– Sam Hartman
Dec 7 '13 at 20:14
3
This answer is simply wrong. Without super() calls in the parents, nothing will happen. @lifeless's answer is the correct one.
– Cerin
Oct 17 '15 at 1:01
4
@Cerin The point of this example is to show how the MRO is constructed. The example is NOT intended to print "firstnsecondthird" or whatever. And the MRO is indeed correct: Fourth.__mro__ == (<class 'main.Fourth'>, <class 'main.Second'>, <class 'main.Third'>, <class 'main.First'>, <type 'object'>)
– rbp
Oct 17 '15 at 10:30
1
@gatoatigrado is right when he says it gets more confusing. I followed his logic to try understading MRO and super in depth. Here is what I learned. Now it is clear to me that, in this case, Second.super will call Third, although Third is not inherited by Second.
– pedrovgp
Jan 31 '17 at 12:26
8
8
It becomes more interesting (and, arguably, more confusing) when you start calling super() in First, Second, and Third [ pastebin.com/ezTyZ5Wa ].
– gatoatigrado
Jul 10 '12 at 0:37
It becomes more interesting (and, arguably, more confusing) when you start calling super() in First, Second, and Third [ pastebin.com/ezTyZ5Wa ].
– gatoatigrado
Jul 10 '12 at 0:37
38
38
I think the lack of super calls in the first classes is a really big problem with this answer; without discussing how/why thats important critical understanding to the question is lost.
– Sam Hartman
Dec 7 '13 at 20:14
I think the lack of super calls in the first classes is a really big problem with this answer; without discussing how/why thats important critical understanding to the question is lost.
– Sam Hartman
Dec 7 '13 at 20:14
3
3
This answer is simply wrong. Without super() calls in the parents, nothing will happen. @lifeless's answer is the correct one.
– Cerin
Oct 17 '15 at 1:01
This answer is simply wrong. Without super() calls in the parents, nothing will happen. @lifeless's answer is the correct one.
– Cerin
Oct 17 '15 at 1:01
4
4
@Cerin The point of this example is to show how the MRO is constructed. The example is NOT intended to print "firstnsecondthird" or whatever. And the MRO is indeed correct: Fourth.__mro__ == (<class 'main.Fourth'>, <class 'main.Second'>, <class 'main.Third'>, <class 'main.First'>, <type 'object'>)
– rbp
Oct 17 '15 at 10:30
@Cerin The point of this example is to show how the MRO is constructed. The example is NOT intended to print "firstnsecondthird" or whatever. And the MRO is indeed correct: Fourth.__mro__ == (<class 'main.Fourth'>, <class 'main.Second'>, <class 'main.Third'>, <class 'main.First'>, <type 'object'>)
– rbp
Oct 17 '15 at 10:30
1
1
@gatoatigrado is right when he says it gets more confusing. I followed his logic to try understading MRO and super in depth. Here is what I learned. Now it is clear to me that, in this case, Second.super will call Third, although Third is not inherited by Second.
– pedrovgp
Jan 31 '17 at 12:26
@gatoatigrado is right when he says it gets more confusing. I followed his logic to try understading MRO and super in depth. Here is what I learned. Now it is clear to me that, in this case, Second.super will call Third, although Third is not inherited by Second.
– pedrovgp
Jan 31 '17 at 12:26
|
show 8 more comments
Your code, and the other answers, are all buggy. They are missing the super()
calls in the first two classes that are required for co-operative subclassing to work.
Here is a fixed version of the 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print("third")
The super()
call finds the next method in the MRO at each step, which is why First and Second have to have it too, otherwise execution stops at the end of Second.__init__()
.
This is what I get:
>>> Third()
second
first
third
51
What to do if these classes need different parameters to initialize themselves?
– calfzhou
May 8 '14 at 9:23
2
"co-operative subclassing"
– Quant Metropolis
Sep 5 '14 at 11:13
2
In this way the init methods of BOTH base classes will get executed, while the original example calls only the first init encountered in the MRO. I guess that is implied by the term "co-operative subclassing", but a clarification would have been useful ('Explicit is better than implicit', you know ;) )
– Quant Metropolis
Sep 5 '14 at 11:19
1
Yes, if you are passing different parameters to a method being called via super, all the implementations of that method going up the MRO towards object() need to have compatible signatures. This can be achieved through keyword parameters: accept more parameters than the method uses, and ignore extra ones. Its generally considered ugly to do this, and for most cases adding new methods is better, but init is (nearly?) unique as a special method name but with user defined parameters.
– lifeless
Dec 1 '14 at 10:15
7
The design of multiple inheritance is really really bad in python. The base classes almost need to know who is going to derive it, and how many other base classes the derived will derive, and in what order... otherwisesuper
will either fail to run (because of parameter mismatch), or it will not call few of the bases (because you didn't writesuper
in one of the base which breaks the link)!
– Nawaz
Nov 9 '16 at 13:12
|
show 2 more comments
Your code, and the other answers, are all buggy. They are missing the super()
calls in the first two classes that are required for co-operative subclassing to work.
Here is a fixed version of the 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print("third")
The super()
call finds the next method in the MRO at each step, which is why First and Second have to have it too, otherwise execution stops at the end of Second.__init__()
.
This is what I get:
>>> Third()
second
first
third
51
What to do if these classes need different parameters to initialize themselves?
– calfzhou
May 8 '14 at 9:23
2
"co-operative subclassing"
– Quant Metropolis
Sep 5 '14 at 11:13
2
In this way the init methods of BOTH base classes will get executed, while the original example calls only the first init encountered in the MRO. I guess that is implied by the term "co-operative subclassing", but a clarification would have been useful ('Explicit is better than implicit', you know ;) )
– Quant Metropolis
Sep 5 '14 at 11:19
1
Yes, if you are passing different parameters to a method being called via super, all the implementations of that method going up the MRO towards object() need to have compatible signatures. This can be achieved through keyword parameters: accept more parameters than the method uses, and ignore extra ones. Its generally considered ugly to do this, and for most cases adding new methods is better, but init is (nearly?) unique as a special method name but with user defined parameters.
– lifeless
Dec 1 '14 at 10:15
7
The design of multiple inheritance is really really bad in python. The base classes almost need to know who is going to derive it, and how many other base classes the derived will derive, and in what order... otherwisesuper
will either fail to run (because of parameter mismatch), or it will not call few of the bases (because you didn't writesuper
in one of the base which breaks the link)!
– Nawaz
Nov 9 '16 at 13:12
|
show 2 more comments
Your code, and the other answers, are all buggy. They are missing the super()
calls in the first two classes that are required for co-operative subclassing to work.
Here is a fixed version of the 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print("third")
The super()
call finds the next method in the MRO at each step, which is why First and Second have to have it too, otherwise execution stops at the end of Second.__init__()
.
This is what I get:
>>> Third()
second
first
third
Your code, and the other answers, are all buggy. They are missing the super()
calls in the first two classes that are required for co-operative subclassing to work.
Here is a fixed version of the 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print("third")
The super()
call finds the next method in the MRO at each step, which is why First and Second have to have it too, otherwise execution stops at the end of Second.__init__()
.
This is what I get:
>>> Third()
second
first
third
edited Dec 9 '17 at 1:33
jojo
3,63122043
3,63122043
answered Apr 30 '13 at 23:54
lifelesslifeless
2,2271115
2,2271115
51
What to do if these classes need different parameters to initialize themselves?
– calfzhou
May 8 '14 at 9:23
2
"co-operative subclassing"
– Quant Metropolis
Sep 5 '14 at 11:13
2
In this way the init methods of BOTH base classes will get executed, while the original example calls only the first init encountered in the MRO. I guess that is implied by the term "co-operative subclassing", but a clarification would have been useful ('Explicit is better than implicit', you know ;) )
– Quant Metropolis
Sep 5 '14 at 11:19
1
Yes, if you are passing different parameters to a method being called via super, all the implementations of that method going up the MRO towards object() need to have compatible signatures. This can be achieved through keyword parameters: accept more parameters than the method uses, and ignore extra ones. Its generally considered ugly to do this, and for most cases adding new methods is better, but init is (nearly?) unique as a special method name but with user defined parameters.
– lifeless
Dec 1 '14 at 10:15
7
The design of multiple inheritance is really really bad in python. The base classes almost need to know who is going to derive it, and how many other base classes the derived will derive, and in what order... otherwisesuper
will either fail to run (because of parameter mismatch), or it will not call few of the bases (because you didn't writesuper
in one of the base which breaks the link)!
– Nawaz
Nov 9 '16 at 13:12
|
show 2 more comments
51
What to do if these classes need different parameters to initialize themselves?
– calfzhou
May 8 '14 at 9:23
2
"co-operative subclassing"
– Quant Metropolis
Sep 5 '14 at 11:13
2
In this way the init methods of BOTH base classes will get executed, while the original example calls only the first init encountered in the MRO. I guess that is implied by the term "co-operative subclassing", but a clarification would have been useful ('Explicit is better than implicit', you know ;) )
– Quant Metropolis
Sep 5 '14 at 11:19
1
Yes, if you are passing different parameters to a method being called via super, all the implementations of that method going up the MRO towards object() need to have compatible signatures. This can be achieved through keyword parameters: accept more parameters than the method uses, and ignore extra ones. Its generally considered ugly to do this, and for most cases adding new methods is better, but init is (nearly?) unique as a special method name but with user defined parameters.
– lifeless
Dec 1 '14 at 10:15
7
The design of multiple inheritance is really really bad in python. The base classes almost need to know who is going to derive it, and how many other base classes the derived will derive, and in what order... otherwisesuper
will either fail to run (because of parameter mismatch), or it will not call few of the bases (because you didn't writesuper
in one of the base which breaks the link)!
– Nawaz
Nov 9 '16 at 13:12
51
51
What to do if these classes need different parameters to initialize themselves?
– calfzhou
May 8 '14 at 9:23
What to do if these classes need different parameters to initialize themselves?
– calfzhou
May 8 '14 at 9:23
2
2
"co-operative subclassing"
– Quant Metropolis
Sep 5 '14 at 11:13
"co-operative subclassing"
– Quant Metropolis
Sep 5 '14 at 11:13
2
2
In this way the init methods of BOTH base classes will get executed, while the original example calls only the first init encountered in the MRO. I guess that is implied by the term "co-operative subclassing", but a clarification would have been useful ('Explicit is better than implicit', you know ;) )
– Quant Metropolis
Sep 5 '14 at 11:19
In this way the init methods of BOTH base classes will get executed, while the original example calls only the first init encountered in the MRO. I guess that is implied by the term "co-operative subclassing", but a clarification would have been useful ('Explicit is better than implicit', you know ;) )
– Quant Metropolis
Sep 5 '14 at 11:19
1
1
Yes, if you are passing different parameters to a method being called via super, all the implementations of that method going up the MRO towards object() need to have compatible signatures. This can be achieved through keyword parameters: accept more parameters than the method uses, and ignore extra ones. Its generally considered ugly to do this, and for most cases adding new methods is better, but init is (nearly?) unique as a special method name but with user defined parameters.
– lifeless
Dec 1 '14 at 10:15
Yes, if you are passing different parameters to a method being called via super, all the implementations of that method going up the MRO towards object() need to have compatible signatures. This can be achieved through keyword parameters: accept more parameters than the method uses, and ignore extra ones. Its generally considered ugly to do this, and for most cases adding new methods is better, but init is (nearly?) unique as a special method name but with user defined parameters.
– lifeless
Dec 1 '14 at 10:15
7
7
The design of multiple inheritance is really really bad in python. The base classes almost need to know who is going to derive it, and how many other base classes the derived will derive, and in what order... otherwise
super
will either fail to run (because of parameter mismatch), or it will not call few of the bases (because you didn't write super
in one of the base which breaks the link)!– Nawaz
Nov 9 '16 at 13:12
The design of multiple inheritance is really really bad in python. The base classes almost need to know who is going to derive it, and how many other base classes the derived will derive, and in what order... otherwise
super
will either fail to run (because of parameter mismatch), or it will not call few of the bases (because you didn't write super
in one of the base which breaks the link)!– Nawaz
Nov 9 '16 at 13:12
|
show 2 more comments
I wanted to elaborate the answer by lifeless a bit because when I started reading about how to use super() in a multiple inheritance hierarchy in Python, I did't get it immediately.
What you need to understand is that super(MyClass, self).__init__()
provides the next __init__
method according to the used Method Resolution Ordering (MRO) algorithm in the context of the complete inheritance hierarchy.
This last part is crucial to understand. Let's consider the example again:
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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
According to this article about Method Resolution Order by Guido van Rossum, the order to resolve __init__
is calculated (before Python 2.3) using a "depth-first left-to-right traversal" :
Third --> First --> object --> Second --> object
After removing all duplicates, except for the last one, we get :
Third --> First --> Second --> object
So, lets follow what happens when we instantiate an instance of the Third
class, e.g. x = Third()
.
According to MRO
__init__
of Third is called first.Next, according to the MRO, inside the
__init__
methodsuper(Third,
resolves to the
self).__init__()__init__
method of First, which
gets called.Inside
__init__
of Firstsuper(First, self).__init__()
calls the__init__
of Second, because that is what the MRO dictates!Inside
__init__
of Secondsuper(Second, self).__init__()
calls
the__init__
of object, which amounts to nothing. After that
"second" is printed.After
super(First, self).__init__()
completed,
"first" is printed.After
super(Third, self).__init__()
completed, "that's it" is printed.
This details out why instantiating Third() results in to :
>>> x = Third()
second
first
that's it
The MRO algorithm has been improved from Python 2.3 onwards to work well in complex cases, but I guess that using the "depth-first left-to-right traversal" + "removing duplicates expect for the last" still works in most cases (please comment if this is not the case). Be sure to read the blog post by Guido!
3
I still do not understand why: Inside init of First super(First, self).__init__() calls the init of Second, because that is what the MRO dictates!
– user389955
Sep 20 '17 at 19:52
@user389955 The object created is of type Third which has all init methods. So if you assume MRO creates a list of all init functions in a specific order, with every super call, you are going one step forward till you reach the end.
– Sreekumar R
Jan 13 '18 at 18:10
9
I think Step 3 needs more explanation: IfThird
did not inherit fromSecond
, thensuper(First, self).__init__
would callobject.__init__
and after returning, "first" would be printed. But becauseThird
inherits from bothFirst
andSecond
, rather than callingobject.__init__
afterFirst.__init__
the MRO dictates that only the final call toobject.__init__
is preserved, and the print statements inFirst
andSecond
are not reached untilobject.__init__
returns. SinceSecond
was the last to callobject.__init__
, it returns insideSecond
before returning inFirst
.
– MountainDrew
Feb 14 '18 at 16:45
2
You nailed it, very good explanation! Kodos!
– Ghasan
Feb 19 '18 at 9:45
Interestingly, PyCharm seems to know all this (its hints talk about which parameters go with which calls to super. It also has some notion of covariance of inputs, so it recognizesList[subclass]
as aList[superclass]
ifsubclass
is a subclass ofsuperclass
(List
comes from thetyping
module of PEP 483 iirc).
– Reb.Cabin
May 9 '18 at 1:58
add a comment |
I wanted to elaborate the answer by lifeless a bit because when I started reading about how to use super() in a multiple inheritance hierarchy in Python, I did't get it immediately.
What you need to understand is that super(MyClass, self).__init__()
provides the next __init__
method according to the used Method Resolution Ordering (MRO) algorithm in the context of the complete inheritance hierarchy.
This last part is crucial to understand. Let's consider the example again:
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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
According to this article about Method Resolution Order by Guido van Rossum, the order to resolve __init__
is calculated (before Python 2.3) using a "depth-first left-to-right traversal" :
Third --> First --> object --> Second --> object
After removing all duplicates, except for the last one, we get :
Third --> First --> Second --> object
So, lets follow what happens when we instantiate an instance of the Third
class, e.g. x = Third()
.
According to MRO
__init__
of Third is called first.Next, according to the MRO, inside the
__init__
methodsuper(Third,
resolves to the
self).__init__()__init__
method of First, which
gets called.Inside
__init__
of Firstsuper(First, self).__init__()
calls the__init__
of Second, because that is what the MRO dictates!Inside
__init__
of Secondsuper(Second, self).__init__()
calls
the__init__
of object, which amounts to nothing. After that
"second" is printed.After
super(First, self).__init__()
completed,
"first" is printed.After
super(Third, self).__init__()
completed, "that's it" is printed.
This details out why instantiating Third() results in to :
>>> x = Third()
second
first
that's it
The MRO algorithm has been improved from Python 2.3 onwards to work well in complex cases, but I guess that using the "depth-first left-to-right traversal" + "removing duplicates expect for the last" still works in most cases (please comment if this is not the case). Be sure to read the blog post by Guido!
3
I still do not understand why: Inside init of First super(First, self).__init__() calls the init of Second, because that is what the MRO dictates!
– user389955
Sep 20 '17 at 19:52
@user389955 The object created is of type Third which has all init methods. So if you assume MRO creates a list of all init functions in a specific order, with every super call, you are going one step forward till you reach the end.
– Sreekumar R
Jan 13 '18 at 18:10
9
I think Step 3 needs more explanation: IfThird
did not inherit fromSecond
, thensuper(First, self).__init__
would callobject.__init__
and after returning, "first" would be printed. But becauseThird
inherits from bothFirst
andSecond
, rather than callingobject.__init__
afterFirst.__init__
the MRO dictates that only the final call toobject.__init__
is preserved, and the print statements inFirst
andSecond
are not reached untilobject.__init__
returns. SinceSecond
was the last to callobject.__init__
, it returns insideSecond
before returning inFirst
.
– MountainDrew
Feb 14 '18 at 16:45
2
You nailed it, very good explanation! Kodos!
– Ghasan
Feb 19 '18 at 9:45
Interestingly, PyCharm seems to know all this (its hints talk about which parameters go with which calls to super. It also has some notion of covariance of inputs, so it recognizesList[subclass]
as aList[superclass]
ifsubclass
is a subclass ofsuperclass
(List
comes from thetyping
module of PEP 483 iirc).
– Reb.Cabin
May 9 '18 at 1:58
add a comment |
I wanted to elaborate the answer by lifeless a bit because when I started reading about how to use super() in a multiple inheritance hierarchy in Python, I did't get it immediately.
What you need to understand is that super(MyClass, self).__init__()
provides the next __init__
method according to the used Method Resolution Ordering (MRO) algorithm in the context of the complete inheritance hierarchy.
This last part is crucial to understand. Let's consider the example again:
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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
According to this article about Method Resolution Order by Guido van Rossum, the order to resolve __init__
is calculated (before Python 2.3) using a "depth-first left-to-right traversal" :
Third --> First --> object --> Second --> object
After removing all duplicates, except for the last one, we get :
Third --> First --> Second --> object
So, lets follow what happens when we instantiate an instance of the Third
class, e.g. x = Third()
.
According to MRO
__init__
of Third is called first.Next, according to the MRO, inside the
__init__
methodsuper(Third,
resolves to the
self).__init__()__init__
method of First, which
gets called.Inside
__init__
of Firstsuper(First, self).__init__()
calls the__init__
of Second, because that is what the MRO dictates!Inside
__init__
of Secondsuper(Second, self).__init__()
calls
the__init__
of object, which amounts to nothing. After that
"second" is printed.After
super(First, self).__init__()
completed,
"first" is printed.After
super(Third, self).__init__()
completed, "that's it" is printed.
This details out why instantiating Third() results in to :
>>> x = Third()
second
first
that's it
The MRO algorithm has been improved from Python 2.3 onwards to work well in complex cases, but I guess that using the "depth-first left-to-right traversal" + "removing duplicates expect for the last" still works in most cases (please comment if this is not the case). Be sure to read the blog post by Guido!
I wanted to elaborate the answer by lifeless a bit because when I started reading about how to use super() in a multiple inheritance hierarchy in Python, I did't get it immediately.
What you need to understand is that super(MyClass, self).__init__()
provides the next __init__
method according to the used Method Resolution Ordering (MRO) algorithm in the context of the complete inheritance hierarchy.
This last part is crucial to understand. Let's consider the example again:
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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
According to this article about Method Resolution Order by Guido van Rossum, the order to resolve __init__
is calculated (before Python 2.3) using a "depth-first left-to-right traversal" :
Third --> First --> object --> Second --> object
After removing all duplicates, except for the last one, we get :
Third --> First --> Second --> object
So, lets follow what happens when we instantiate an instance of the Third
class, e.g. x = Third()
.
According to MRO
__init__
of Third is called first.Next, according to the MRO, inside the
__init__
methodsuper(Third,
resolves to the
self).__init__()__init__
method of First, which
gets called.Inside
__init__
of Firstsuper(First, self).__init__()
calls the__init__
of Second, because that is what the MRO dictates!Inside
__init__
of Secondsuper(Second, self).__init__()
calls
the__init__
of object, which amounts to nothing. After that
"second" is printed.After
super(First, self).__init__()
completed,
"first" is printed.After
super(Third, self).__init__()
completed, "that's it" is printed.
This details out why instantiating Third() results in to :
>>> x = Third()
second
first
that's it
The MRO algorithm has been improved from Python 2.3 onwards to work well in complex cases, but I guess that using the "depth-first left-to-right traversal" + "removing duplicates expect for the last" still works in most cases (please comment if this is not the case). Be sure to read the blog post by Guido!
edited May 23 '17 at 11:47
Community♦
11
11
answered May 12 '15 at 9:51
VisionscaperVisionscaper
2,38611821
2,38611821
3
I still do not understand why: Inside init of First super(First, self).__init__() calls the init of Second, because that is what the MRO dictates!
– user389955
Sep 20 '17 at 19:52
@user389955 The object created is of type Third which has all init methods. So if you assume MRO creates a list of all init functions in a specific order, with every super call, you are going one step forward till you reach the end.
– Sreekumar R
Jan 13 '18 at 18:10
9
I think Step 3 needs more explanation: IfThird
did not inherit fromSecond
, thensuper(First, self).__init__
would callobject.__init__
and after returning, "first" would be printed. But becauseThird
inherits from bothFirst
andSecond
, rather than callingobject.__init__
afterFirst.__init__
the MRO dictates that only the final call toobject.__init__
is preserved, and the print statements inFirst
andSecond
are not reached untilobject.__init__
returns. SinceSecond
was the last to callobject.__init__
, it returns insideSecond
before returning inFirst
.
– MountainDrew
Feb 14 '18 at 16:45
2
You nailed it, very good explanation! Kodos!
– Ghasan
Feb 19 '18 at 9:45
Interestingly, PyCharm seems to know all this (its hints talk about which parameters go with which calls to super. It also has some notion of covariance of inputs, so it recognizesList[subclass]
as aList[superclass]
ifsubclass
is a subclass ofsuperclass
(List
comes from thetyping
module of PEP 483 iirc).
– Reb.Cabin
May 9 '18 at 1:58
add a comment |
3
I still do not understand why: Inside init of First super(First, self).__init__() calls the init of Second, because that is what the MRO dictates!
– user389955
Sep 20 '17 at 19:52
@user389955 The object created is of type Third which has all init methods. So if you assume MRO creates a list of all init functions in a specific order, with every super call, you are going one step forward till you reach the end.
– Sreekumar R
Jan 13 '18 at 18:10
9
I think Step 3 needs more explanation: IfThird
did not inherit fromSecond
, thensuper(First, self).__init__
would callobject.__init__
and after returning, "first" would be printed. But becauseThird
inherits from bothFirst
andSecond
, rather than callingobject.__init__
afterFirst.__init__
the MRO dictates that only the final call toobject.__init__
is preserved, and the print statements inFirst
andSecond
are not reached untilobject.__init__
returns. SinceSecond
was the last to callobject.__init__
, it returns insideSecond
before returning inFirst
.
– MountainDrew
Feb 14 '18 at 16:45
2
You nailed it, very good explanation! Kodos!
– Ghasan
Feb 19 '18 at 9:45
Interestingly, PyCharm seems to know all this (its hints talk about which parameters go with which calls to super. It also has some notion of covariance of inputs, so it recognizesList[subclass]
as aList[superclass]
ifsubclass
is a subclass ofsuperclass
(List
comes from thetyping
module of PEP 483 iirc).
– Reb.Cabin
May 9 '18 at 1:58
3
3
I still do not understand why: Inside init of First super(First, self).__init__() calls the init of Second, because that is what the MRO dictates!
– user389955
Sep 20 '17 at 19:52
I still do not understand why: Inside init of First super(First, self).__init__() calls the init of Second, because that is what the MRO dictates!
– user389955
Sep 20 '17 at 19:52
@user389955 The object created is of type Third which has all init methods. So if you assume MRO creates a list of all init functions in a specific order, with every super call, you are going one step forward till you reach the end.
– Sreekumar R
Jan 13 '18 at 18:10
@user389955 The object created is of type Third which has all init methods. So if you assume MRO creates a list of all init functions in a specific order, with every super call, you are going one step forward till you reach the end.
– Sreekumar R
Jan 13 '18 at 18:10
9
9
I think Step 3 needs more explanation: If
Third
did not inherit from Second
, then super(First, self).__init__
would call object.__init__
and after returning, "first" would be printed. But because Third
inherits from both First
and Second
, rather than calling object.__init__
after First.__init__
the MRO dictates that only the final call to object.__init__
is preserved, and the print statements in First
and Second
are not reached until object.__init__
returns. Since Second
was the last to call object.__init__
, it returns inside Second
before returning in First
.– MountainDrew
Feb 14 '18 at 16:45
I think Step 3 needs more explanation: If
Third
did not inherit from Second
, then super(First, self).__init__
would call object.__init__
and after returning, "first" would be printed. But because Third
inherits from both First
and Second
, rather than calling object.__init__
after First.__init__
the MRO dictates that only the final call to object.__init__
is preserved, and the print statements in First
and Second
are not reached until object.__init__
returns. Since Second
was the last to call object.__init__
, it returns inside Second
before returning in First
.– MountainDrew
Feb 14 '18 at 16:45
2
2
You nailed it, very good explanation! Kodos!
– Ghasan
Feb 19 '18 at 9:45
You nailed it, very good explanation! Kodos!
– Ghasan
Feb 19 '18 at 9:45
Interestingly, PyCharm seems to know all this (its hints talk about which parameters go with which calls to super. It also has some notion of covariance of inputs, so it recognizes
List[subclass]
as a List[superclass]
if subclass
is a subclass of superclass
(List
comes from the typing
module of PEP 483 iirc).– Reb.Cabin
May 9 '18 at 1:58
Interestingly, PyCharm seems to know all this (its hints talk about which parameters go with which calls to super. It also has some notion of covariance of inputs, so it recognizes
List[subclass]
as a List[superclass]
if subclass
is a subclass of superclass
(List
comes from the typing
module of PEP 483 iirc).– Reb.Cabin
May 9 '18 at 1:58
add a comment |
This is known as the Diamond Problem, the page has an entry on Python, but in short, Python will call the superclass's methods from left to right.
This is not the Diamond Problem. The Diamond Problem involves four classes and the OP's question only involves three.
– Ian Goodfellow
Aug 6 '11 at 16:14
121
object
is the fourth
– GP89
Oct 26 '11 at 13:30
add a comment |
This is known as the Diamond Problem, the page has an entry on Python, but in short, Python will call the superclass's methods from left to right.
This is not the Diamond Problem. The Diamond Problem involves four classes and the OP's question only involves three.
– Ian Goodfellow
Aug 6 '11 at 16:14
121
object
is the fourth
– GP89
Oct 26 '11 at 13:30
add a comment |
This is known as the Diamond Problem, the page has an entry on Python, but in short, Python will call the superclass's methods from left to right.
This is known as the Diamond Problem, the page has an entry on Python, but in short, Python will call the superclass's methods from left to right.
edited Aug 2 '10 at 9:52
Peter Mortensen
13.5k1983111
13.5k1983111
answered Jul 18 '10 at 21:50
monoceresmonoceres
2,53522452
2,53522452
This is not the Diamond Problem. The Diamond Problem involves four classes and the OP's question only involves three.
– Ian Goodfellow
Aug 6 '11 at 16:14
121
object
is the fourth
– GP89
Oct 26 '11 at 13:30
add a comment |
This is not the Diamond Problem. The Diamond Problem involves four classes and the OP's question only involves three.
– Ian Goodfellow
Aug 6 '11 at 16:14
121
object
is the fourth
– GP89
Oct 26 '11 at 13:30
This is not the Diamond Problem. The Diamond Problem involves four classes and the OP's question only involves three.
– Ian Goodfellow
Aug 6 '11 at 16:14
This is not the Diamond Problem. The Diamond Problem involves four classes and the OP's question only involves three.
– Ian Goodfellow
Aug 6 '11 at 16:14
121
121
object
is the fourth– GP89
Oct 26 '11 at 13:30
object
is the fourth– GP89
Oct 26 '11 at 13:30
add a comment |
This is to how I solved to issue of having multiple inheritance with different variables for initialization and having multiple MixIns with the same function call. I had to explicitly add variables to passed **kwargs and add a MixIn interface to be an endpoint for super calls.
Here A
is an extendable base class and B
and C
are MixIn classes both who provide function f
. A
and B
both expect parameter v
in their __init__
and C
expects w
.
The function f
takes one parameter y
. Q
inherits from all three classes. MixInF
is the mixin interface for B
and C
.
- IPython NoteBook Of This Code
- Github Repo with code example
class A(object):
def __init__(self, v, *args, **kwargs):
print "A:init:v[{0}]".format(v)
kwargs['v']=v
super(A, self).__init__(*args, **kwargs)
self.v = v
class MixInF(object):
def __init__(self, *args, **kwargs):
print "IObject:init"
def f(self, y):
print "IObject:y[{0}]".format(y)
class B(MixInF):
def __init__(self, v, *args, **kwargs):
print "B:init:v[{0}]".format(v)
kwargs['v']=v
super(B, self).__init__(*args, **kwargs)
self.v = v
def f(self, y):
print "B:f:v[{0}]:y[{1}]".format(self.v, y)
super(B, self).f(y)
class C(MixInF):
def __init__(self, w, *args, **kwargs):
print "C:init:w[{0}]".format(w)
kwargs['w']=w
super(C, self).__init__(*args, **kwargs)
self.w = w
def f(self, y):
print "C:f:w[{0}]:y[{1}]".format(self.w, y)
super(C, self).f(y)
class Q(C,B,A):
def __init__(self, v, w):
super(Q, self).__init__(v=v, w=w)
def f(self, y):
print "Q:f:y[{0}]".format(y)
super(Q, self).f(y)
I think this should perhaps be a separate question-and-answer, as the MRO is a large enough topic on its own without getting into dealing with varying arguments across functions with inheritance (multiple inheritance is a special case of that).
– lifeless
Dec 1 '14 at 10:21
6
Theoretically, yes. Practically, this scenario has come up every time I've encountered Diamond inheritance in python, so I added it here. Since, this is where I go every time I cannot cleanly avoid diamond inheritance. Here are some extra links for future me: rhettinger.wordpress.com/2011/05/26/super-considered-super code.activestate.com/recipes/…
– brent.payne
Dec 3 '14 at 20:40
What we want is programs with semantically meaningful parameter names. But in this example almost all the parameters are anonymously named, which will make it much more difficult for the original programmer to document the code and for another programmer to read the code.
– Arthur
Nov 29 '16 at 13:55
A pull request to the github repo with descriptive names would be appreciated
– brent.payne
Nov 29 '16 at 20:41
@brent.payne I think @Arthur meant that your whole approach relies on usingargs
/kwargs
rather than named parameters.
– max
Jun 11 '17 at 23:00
|
show 1 more comment
This is to how I solved to issue of having multiple inheritance with different variables for initialization and having multiple MixIns with the same function call. I had to explicitly add variables to passed **kwargs and add a MixIn interface to be an endpoint for super calls.
Here A
is an extendable base class and B
and C
are MixIn classes both who provide function f
. A
and B
both expect parameter v
in their __init__
and C
expects w
.
The function f
takes one parameter y
. Q
inherits from all three classes. MixInF
is the mixin interface for B
and C
.
- IPython NoteBook Of This Code
- Github Repo with code example
class A(object):
def __init__(self, v, *args, **kwargs):
print "A:init:v[{0}]".format(v)
kwargs['v']=v
super(A, self).__init__(*args, **kwargs)
self.v = v
class MixInF(object):
def __init__(self, *args, **kwargs):
print "IObject:init"
def f(self, y):
print "IObject:y[{0}]".format(y)
class B(MixInF):
def __init__(self, v, *args, **kwargs):
print "B:init:v[{0}]".format(v)
kwargs['v']=v
super(B, self).__init__(*args, **kwargs)
self.v = v
def f(self, y):
print "B:f:v[{0}]:y[{1}]".format(self.v, y)
super(B, self).f(y)
class C(MixInF):
def __init__(self, w, *args, **kwargs):
print "C:init:w[{0}]".format(w)
kwargs['w']=w
super(C, self).__init__(*args, **kwargs)
self.w = w
def f(self, y):
print "C:f:w[{0}]:y[{1}]".format(self.w, y)
super(C, self).f(y)
class Q(C,B,A):
def __init__(self, v, w):
super(Q, self).__init__(v=v, w=w)
def f(self, y):
print "Q:f:y[{0}]".format(y)
super(Q, self).f(y)
I think this should perhaps be a separate question-and-answer, as the MRO is a large enough topic on its own without getting into dealing with varying arguments across functions with inheritance (multiple inheritance is a special case of that).
– lifeless
Dec 1 '14 at 10:21
6
Theoretically, yes. Practically, this scenario has come up every time I've encountered Diamond inheritance in python, so I added it here. Since, this is where I go every time I cannot cleanly avoid diamond inheritance. Here are some extra links for future me: rhettinger.wordpress.com/2011/05/26/super-considered-super code.activestate.com/recipes/…
– brent.payne
Dec 3 '14 at 20:40
What we want is programs with semantically meaningful parameter names. But in this example almost all the parameters are anonymously named, which will make it much more difficult for the original programmer to document the code and for another programmer to read the code.
– Arthur
Nov 29 '16 at 13:55
A pull request to the github repo with descriptive names would be appreciated
– brent.payne
Nov 29 '16 at 20:41
@brent.payne I think @Arthur meant that your whole approach relies on usingargs
/kwargs
rather than named parameters.
– max
Jun 11 '17 at 23:00
|
show 1 more comment
This is to how I solved to issue of having multiple inheritance with different variables for initialization and having multiple MixIns with the same function call. I had to explicitly add variables to passed **kwargs and add a MixIn interface to be an endpoint for super calls.
Here A
is an extendable base class and B
and C
are MixIn classes both who provide function f
. A
and B
both expect parameter v
in their __init__
and C
expects w
.
The function f
takes one parameter y
. Q
inherits from all three classes. MixInF
is the mixin interface for B
and C
.
- IPython NoteBook Of This Code
- Github Repo with code example
class A(object):
def __init__(self, v, *args, **kwargs):
print "A:init:v[{0}]".format(v)
kwargs['v']=v
super(A, self).__init__(*args, **kwargs)
self.v = v
class MixInF(object):
def __init__(self, *args, **kwargs):
print "IObject:init"
def f(self, y):
print "IObject:y[{0}]".format(y)
class B(MixInF):
def __init__(self, v, *args, **kwargs):
print "B:init:v[{0}]".format(v)
kwargs['v']=v
super(B, self).__init__(*args, **kwargs)
self.v = v
def f(self, y):
print "B:f:v[{0}]:y[{1}]".format(self.v, y)
super(B, self).f(y)
class C(MixInF):
def __init__(self, w, *args, **kwargs):
print "C:init:w[{0}]".format(w)
kwargs['w']=w
super(C, self).__init__(*args, **kwargs)
self.w = w
def f(self, y):
print "C:f:w[{0}]:y[{1}]".format(self.w, y)
super(C, self).f(y)
class Q(C,B,A):
def __init__(self, v, w):
super(Q, self).__init__(v=v, w=w)
def f(self, y):
print "Q:f:y[{0}]".format(y)
super(Q, self).f(y)
This is to how I solved to issue of having multiple inheritance with different variables for initialization and having multiple MixIns with the same function call. I had to explicitly add variables to passed **kwargs and add a MixIn interface to be an endpoint for super calls.
Here A
is an extendable base class and B
and C
are MixIn classes both who provide function f
. A
and B
both expect parameter v
in their __init__
and C
expects w
.
The function f
takes one parameter y
. Q
inherits from all three classes. MixInF
is the mixin interface for B
and C
.
- IPython NoteBook Of This Code
- Github Repo with code example
class A(object):
def __init__(self, v, *args, **kwargs):
print "A:init:v[{0}]".format(v)
kwargs['v']=v
super(A, self).__init__(*args, **kwargs)
self.v = v
class MixInF(object):
def __init__(self, *args, **kwargs):
print "IObject:init"
def f(self, y):
print "IObject:y[{0}]".format(y)
class B(MixInF):
def __init__(self, v, *args, **kwargs):
print "B:init:v[{0}]".format(v)
kwargs['v']=v
super(B, self).__init__(*args, **kwargs)
self.v = v
def f(self, y):
print "B:f:v[{0}]:y[{1}]".format(self.v, y)
super(B, self).f(y)
class C(MixInF):
def __init__(self, w, *args, **kwargs):
print "C:init:w[{0}]".format(w)
kwargs['w']=w
super(C, self).__init__(*args, **kwargs)
self.w = w
def f(self, y):
print "C:f:w[{0}]:y[{1}]".format(self.w, y)
super(C, self).f(y)
class Q(C,B,A):
def __init__(self, v, w):
super(Q, self).__init__(v=v, w=w)
def f(self, y):
print "Q:f:y[{0}]".format(y)
super(Q, self).f(y)
answered Aug 17 '14 at 19:22
brent.paynebrent.payne
2,71311716
2,71311716
I think this should perhaps be a separate question-and-answer, as the MRO is a large enough topic on its own without getting into dealing with varying arguments across functions with inheritance (multiple inheritance is a special case of that).
– lifeless
Dec 1 '14 at 10:21
6
Theoretically, yes. Practically, this scenario has come up every time I've encountered Diamond inheritance in python, so I added it here. Since, this is where I go every time I cannot cleanly avoid diamond inheritance. Here are some extra links for future me: rhettinger.wordpress.com/2011/05/26/super-considered-super code.activestate.com/recipes/…
– brent.payne
Dec 3 '14 at 20:40
What we want is programs with semantically meaningful parameter names. But in this example almost all the parameters are anonymously named, which will make it much more difficult for the original programmer to document the code and for another programmer to read the code.
– Arthur
Nov 29 '16 at 13:55
A pull request to the github repo with descriptive names would be appreciated
– brent.payne
Nov 29 '16 at 20:41
@brent.payne I think @Arthur meant that your whole approach relies on usingargs
/kwargs
rather than named parameters.
– max
Jun 11 '17 at 23:00
|
show 1 more comment
I think this should perhaps be a separate question-and-answer, as the MRO is a large enough topic on its own without getting into dealing with varying arguments across functions with inheritance (multiple inheritance is a special case of that).
– lifeless
Dec 1 '14 at 10:21
6
Theoretically, yes. Practically, this scenario has come up every time I've encountered Diamond inheritance in python, so I added it here. Since, this is where I go every time I cannot cleanly avoid diamond inheritance. Here are some extra links for future me: rhettinger.wordpress.com/2011/05/26/super-considered-super code.activestate.com/recipes/…
– brent.payne
Dec 3 '14 at 20:40
What we want is programs with semantically meaningful parameter names. But in this example almost all the parameters are anonymously named, which will make it much more difficult for the original programmer to document the code and for another programmer to read the code.
– Arthur
Nov 29 '16 at 13:55
A pull request to the github repo with descriptive names would be appreciated
– brent.payne
Nov 29 '16 at 20:41
@brent.payne I think @Arthur meant that your whole approach relies on usingargs
/kwargs
rather than named parameters.
– max
Jun 11 '17 at 23:00
I think this should perhaps be a separate question-and-answer, as the MRO is a large enough topic on its own without getting into dealing with varying arguments across functions with inheritance (multiple inheritance is a special case of that).
– lifeless
Dec 1 '14 at 10:21
I think this should perhaps be a separate question-and-answer, as the MRO is a large enough topic on its own without getting into dealing with varying arguments across functions with inheritance (multiple inheritance is a special case of that).
– lifeless
Dec 1 '14 at 10:21
6
6
Theoretically, yes. Practically, this scenario has come up every time I've encountered Diamond inheritance in python, so I added it here. Since, this is where I go every time I cannot cleanly avoid diamond inheritance. Here are some extra links for future me: rhettinger.wordpress.com/2011/05/26/super-considered-super code.activestate.com/recipes/…
– brent.payne
Dec 3 '14 at 20:40
Theoretically, yes. Practically, this scenario has come up every time I've encountered Diamond inheritance in python, so I added it here. Since, this is where I go every time I cannot cleanly avoid diamond inheritance. Here are some extra links for future me: rhettinger.wordpress.com/2011/05/26/super-considered-super code.activestate.com/recipes/…
– brent.payne
Dec 3 '14 at 20:40
What we want is programs with semantically meaningful parameter names. But in this example almost all the parameters are anonymously named, which will make it much more difficult for the original programmer to document the code and for another programmer to read the code.
– Arthur
Nov 29 '16 at 13:55
What we want is programs with semantically meaningful parameter names. But in this example almost all the parameters are anonymously named, which will make it much more difficult for the original programmer to document the code and for another programmer to read the code.
– Arthur
Nov 29 '16 at 13:55
A pull request to the github repo with descriptive names would be appreciated
– brent.payne
Nov 29 '16 at 20:41
A pull request to the github repo with descriptive names would be appreciated
– brent.payne
Nov 29 '16 at 20:41
@brent.payne I think @Arthur meant that your whole approach relies on using
args
/ kwargs
rather than named parameters.– max
Jun 11 '17 at 23:00
@brent.payne I think @Arthur meant that your whole approach relies on using
args
/ kwargs
rather than named parameters.– max
Jun 11 '17 at 23:00
|
show 1 more comment
I understand this doesn't directly answer the super()
question, but I feel it's relevant enough to share.
There is also a way to directly call each inherited class:
class First(object):
def __init__(self):
print '1'
class Second(object):
def __init__(self):
print '2'
class Third(First, Second):
def __init__(self):
Second.__init__(self)
Just note that if you do it this way, you'll have to call each manually as I'm pretty sure First
's __init__()
won't be called.
3
It won't be called because you did not call each inherited class. The problem is rather that ifFirst
andSecond
are both inheriting another class and calling it directly then this common class (starting point of the diamond) is called twice. super is avoiding this.
– Trilarion
Jul 29 '14 at 12:04
@Trilarion Yea, I was confident it wouldn't. However, I didn't definitively know and I didn't want to state as if I did even though it was very unlikely. That's a good point about theobject
being called twice. I didn't think about that. I just wanted to make the point that you call parent classes directly.
– Seaux
Jul 30 '14 at 18:58
Unfortunately, this breaks if init tries to access any private methods :(
– Erik Aronesty
May 10 '18 at 21:29
add a comment |
I understand this doesn't directly answer the super()
question, but I feel it's relevant enough to share.
There is also a way to directly call each inherited class:
class First(object):
def __init__(self):
print '1'
class Second(object):
def __init__(self):
print '2'
class Third(First, Second):
def __init__(self):
Second.__init__(self)
Just note that if you do it this way, you'll have to call each manually as I'm pretty sure First
's __init__()
won't be called.
3
It won't be called because you did not call each inherited class. The problem is rather that ifFirst
andSecond
are both inheriting another class and calling it directly then this common class (starting point of the diamond) is called twice. super is avoiding this.
– Trilarion
Jul 29 '14 at 12:04
@Trilarion Yea, I was confident it wouldn't. However, I didn't definitively know and I didn't want to state as if I did even though it was very unlikely. That's a good point about theobject
being called twice. I didn't think about that. I just wanted to make the point that you call parent classes directly.
– Seaux
Jul 30 '14 at 18:58
Unfortunately, this breaks if init tries to access any private methods :(
– Erik Aronesty
May 10 '18 at 21:29
add a comment |
I understand this doesn't directly answer the super()
question, but I feel it's relevant enough to share.
There is also a way to directly call each inherited class:
class First(object):
def __init__(self):
print '1'
class Second(object):
def __init__(self):
print '2'
class Third(First, Second):
def __init__(self):
Second.__init__(self)
Just note that if you do it this way, you'll have to call each manually as I'm pretty sure First
's __init__()
won't be called.
I understand this doesn't directly answer the super()
question, but I feel it's relevant enough to share.
There is also a way to directly call each inherited class:
class First(object):
def __init__(self):
print '1'
class Second(object):
def __init__(self):
print '2'
class Third(First, Second):
def __init__(self):
Second.__init__(self)
Just note that if you do it this way, you'll have to call each manually as I'm pretty sure First
's __init__()
won't be called.
edited Dec 9 '17 at 1:31
sfjac
4,73042851
4,73042851
answered Jan 19 '14 at 17:22
SeauxSeaux
2,60121827
2,60121827
3
It won't be called because you did not call each inherited class. The problem is rather that ifFirst
andSecond
are both inheriting another class and calling it directly then this common class (starting point of the diamond) is called twice. super is avoiding this.
– Trilarion
Jul 29 '14 at 12:04
@Trilarion Yea, I was confident it wouldn't. However, I didn't definitively know and I didn't want to state as if I did even though it was very unlikely. That's a good point about theobject
being called twice. I didn't think about that. I just wanted to make the point that you call parent classes directly.
– Seaux
Jul 30 '14 at 18:58
Unfortunately, this breaks if init tries to access any private methods :(
– Erik Aronesty
May 10 '18 at 21:29
add a comment |
3
It won't be called because you did not call each inherited class. The problem is rather that ifFirst
andSecond
are both inheriting another class and calling it directly then this common class (starting point of the diamond) is called twice. super is avoiding this.
– Trilarion
Jul 29 '14 at 12:04
@Trilarion Yea, I was confident it wouldn't. However, I didn't definitively know and I didn't want to state as if I did even though it was very unlikely. That's a good point about theobject
being called twice. I didn't think about that. I just wanted to make the point that you call parent classes directly.
– Seaux
Jul 30 '14 at 18:58
Unfortunately, this breaks if init tries to access any private methods :(
– Erik Aronesty
May 10 '18 at 21:29
3
3
It won't be called because you did not call each inherited class. The problem is rather that if
First
and Second
are both inheriting another class and calling it directly then this common class (starting point of the diamond) is called twice. super is avoiding this.– Trilarion
Jul 29 '14 at 12:04
It won't be called because you did not call each inherited class. The problem is rather that if
First
and Second
are both inheriting another class and calling it directly then this common class (starting point of the diamond) is called twice. super is avoiding this.– Trilarion
Jul 29 '14 at 12:04
@Trilarion Yea, I was confident it wouldn't. However, I didn't definitively know and I didn't want to state as if I did even though it was very unlikely. That's a good point about the
object
being called twice. I didn't think about that. I just wanted to make the point that you call parent classes directly.– Seaux
Jul 30 '14 at 18:58
@Trilarion Yea, I was confident it wouldn't. However, I didn't definitively know and I didn't want to state as if I did even though it was very unlikely. That's a good point about the
object
being called twice. I didn't think about that. I just wanted to make the point that you call parent classes directly.– Seaux
Jul 30 '14 at 18:58
Unfortunately, this breaks if init tries to access any private methods :(
– Erik Aronesty
May 10 '18 at 21:29
Unfortunately, this breaks if init tries to access any private methods :(
– Erik Aronesty
May 10 '18 at 21:29
add a comment |
About @calfzhou's comment, you can use, as usually, **kwargs
:
Online running example
class A(object):
def __init__(self, a, *args, **kwargs):
print("A", a)
class B(A):
def __init__(self, b, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
print("B", b)
class A1(A):
def __init__(self, a1, *args, **kwargs):
super(A1, self).__init__(*args, **kwargs)
print("A1", a1)
class B1(A1, B):
def __init__(self, b1, *args, **kwargs):
super(B1, self).__init__(*args, **kwargs)
print("B1", b1)
B1(a1=6, b1=5, b="hello", a=None)
Result:
A None
B hello
A1 6
B1 5
You can also use them positionally:
B1(5, 6, b="hello", a=None)
but you have to remember the MRO, it's really confusing.
I can be a little annoying, but I noticed that people forgot every time to use *args
and **kwargs
when they override a method, while it's one of few really useful and sane use of these 'magic variables'.
Wow that's really ugly. It's a shame you can't just say which specific superclass you want to call. Still, this gives me even more incentive to use composition and avoid multiple inheritance like the plague.
– Tom Busby
Feb 6 '17 at 15:55
add a comment |
About @calfzhou's comment, you can use, as usually, **kwargs
:
Online running example
class A(object):
def __init__(self, a, *args, **kwargs):
print("A", a)
class B(A):
def __init__(self, b, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
print("B", b)
class A1(A):
def __init__(self, a1, *args, **kwargs):
super(A1, self).__init__(*args, **kwargs)
print("A1", a1)
class B1(A1, B):
def __init__(self, b1, *args, **kwargs):
super(B1, self).__init__(*args, **kwargs)
print("B1", b1)
B1(a1=6, b1=5, b="hello", a=None)
Result:
A None
B hello
A1 6
B1 5
You can also use them positionally:
B1(5, 6, b="hello", a=None)
but you have to remember the MRO, it's really confusing.
I can be a little annoying, but I noticed that people forgot every time to use *args
and **kwargs
when they override a method, while it's one of few really useful and sane use of these 'magic variables'.
Wow that's really ugly. It's a shame you can't just say which specific superclass you want to call. Still, this gives me even more incentive to use composition and avoid multiple inheritance like the plague.
– Tom Busby
Feb 6 '17 at 15:55
add a comment |
About @calfzhou's comment, you can use, as usually, **kwargs
:
Online running example
class A(object):
def __init__(self, a, *args, **kwargs):
print("A", a)
class B(A):
def __init__(self, b, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
print("B", b)
class A1(A):
def __init__(self, a1, *args, **kwargs):
super(A1, self).__init__(*args, **kwargs)
print("A1", a1)
class B1(A1, B):
def __init__(self, b1, *args, **kwargs):
super(B1, self).__init__(*args, **kwargs)
print("B1", b1)
B1(a1=6, b1=5, b="hello", a=None)
Result:
A None
B hello
A1 6
B1 5
You can also use them positionally:
B1(5, 6, b="hello", a=None)
but you have to remember the MRO, it's really confusing.
I can be a little annoying, but I noticed that people forgot every time to use *args
and **kwargs
when they override a method, while it's one of few really useful and sane use of these 'magic variables'.
About @calfzhou's comment, you can use, as usually, **kwargs
:
Online running example
class A(object):
def __init__(self, a, *args, **kwargs):
print("A", a)
class B(A):
def __init__(self, b, *args, **kwargs):
super(B, self).__init__(*args, **kwargs)
print("B", b)
class A1(A):
def __init__(self, a1, *args, **kwargs):
super(A1, self).__init__(*args, **kwargs)
print("A1", a1)
class B1(A1, B):
def __init__(self, b1, *args, **kwargs):
super(B1, self).__init__(*args, **kwargs)
print("B1", b1)
B1(a1=6, b1=5, b="hello", a=None)
Result:
A None
B hello
A1 6
B1 5
You can also use them positionally:
B1(5, 6, b="hello", a=None)
but you have to remember the MRO, it's really confusing.
I can be a little annoying, but I noticed that people forgot every time to use *args
and **kwargs
when they override a method, while it's one of few really useful and sane use of these 'magic variables'.
answered Apr 21 '16 at 21:33
Marco SullaMarco Sulla
7,90052850
7,90052850
Wow that's really ugly. It's a shame you can't just say which specific superclass you want to call. Still, this gives me even more incentive to use composition and avoid multiple inheritance like the plague.
– Tom Busby
Feb 6 '17 at 15:55
add a comment |
Wow that's really ugly. It's a shame you can't just say which specific superclass you want to call. Still, this gives me even more incentive to use composition and avoid multiple inheritance like the plague.
– Tom Busby
Feb 6 '17 at 15:55
Wow that's really ugly. It's a shame you can't just say which specific superclass you want to call. Still, this gives me even more incentive to use composition and avoid multiple inheritance like the plague.
– Tom Busby
Feb 6 '17 at 15:55
Wow that's really ugly. It's a shame you can't just say which specific superclass you want to call. Still, this gives me even more incentive to use composition and avoid multiple inheritance like the plague.
– Tom Busby
Feb 6 '17 at 15:55
add a comment |
Overall
Assuming everything descends from object
(you are on your own if it doesn't), Python computes a method resolution order (MRO) based on your class inheritance tree. The MRO satisfies 3 properties:
- Children of a class come before their parents
- Left parents come before right parents
- A class only appears once in the MRO
If no such ordering exists, Python errors. The inner workings of this is a C3 Linerization of the classes ancestry. Read all about it here: https://www.python.org/download/releases/2.3/mro/
Thus, in both of the examples below, it is:
- Child
- Left
- Right
- Parent
When a method is called, the first occurrence of that method in the MRO is the one that is called. Any class that doesn't implement that method is skipped. Any call to super
within that method will call the next occurrence of that method in the MRO. Consequently, it matters both what order you place classes in inheritance, and where you put the calls to super
in the methods.
With super
first in each method
class Parent(object):
def __init__(self):
super(Parent, self).__init__()
print "parent"
class Left(Parent):
def __init__(self):
super(Left, self).__init__()
print "left"
class Right(Parent):
def __init__(self):
super(Right, self).__init__()
print "right"
class Child(Left, Right):
def __init__(self):
super(Child, self).__init__()
print "child"
Child()
Outputs:
parent
right
left
child
With super
last in each method
class Parent(object):
def __init__(self):
print "parent"
super(Parent, self).__init__()
class Left(Parent):
def __init__(self):
print "left"
super(Left, self).__init__()
class Right(Parent):
def __init__(self):
print "right"
super(Right, self).__init__()
class Child(Left, Right):
def __init__(self):
print "child"
super(Child, self).__init__()
Child()
Outputs:
child
left
right
parent
I see that you can accessLeft
usingsuper()
fromChild
. suppose I want to accessRight
from insideChild
. Is there a way to accessRight
fromChild
using super? Or should I directly calledRight
from insidesuper
?
– alpha_989
Apr 15 '18 at 22:21
3
@alpha_989 If you want to access the method of a particular class only, you should reference that class directly rather than using super. Super is about following the chain of inheritance, not getting to a specific class's method.
– Zags
May 6 '18 at 12:04
Thanks for explicitly mentioning 'A class only appears once in the MRO'. This solved my problem. Now I finally understand how multiple inheritance works. Somebody needed to mention the properties of MRO!
– Tushar Vazirani
Nov 19 '18 at 20:25
add a comment |
Overall
Assuming everything descends from object
(you are on your own if it doesn't), Python computes a method resolution order (MRO) based on your class inheritance tree. The MRO satisfies 3 properties:
- Children of a class come before their parents
- Left parents come before right parents
- A class only appears once in the MRO
If no such ordering exists, Python errors. The inner workings of this is a C3 Linerization of the classes ancestry. Read all about it here: https://www.python.org/download/releases/2.3/mro/
Thus, in both of the examples below, it is:
- Child
- Left
- Right
- Parent
When a method is called, the first occurrence of that method in the MRO is the one that is called. Any class that doesn't implement that method is skipped. Any call to super
within that method will call the next occurrence of that method in the MRO. Consequently, it matters both what order you place classes in inheritance, and where you put the calls to super
in the methods.
With super
first in each method
class Parent(object):
def __init__(self):
super(Parent, self).__init__()
print "parent"
class Left(Parent):
def __init__(self):
super(Left, self).__init__()
print "left"
class Right(Parent):
def __init__(self):
super(Right, self).__init__()
print "right"
class Child(Left, Right):
def __init__(self):
super(Child, self).__init__()
print "child"
Child()
Outputs:
parent
right
left
child
With super
last in each method
class Parent(object):
def __init__(self):
print "parent"
super(Parent, self).__init__()
class Left(Parent):
def __init__(self):
print "left"
super(Left, self).__init__()
class Right(Parent):
def __init__(self):
print "right"
super(Right, self).__init__()
class Child(Left, Right):
def __init__(self):
print "child"
super(Child, self).__init__()
Child()
Outputs:
child
left
right
parent
I see that you can accessLeft
usingsuper()
fromChild
. suppose I want to accessRight
from insideChild
. Is there a way to accessRight
fromChild
using super? Or should I directly calledRight
from insidesuper
?
– alpha_989
Apr 15 '18 at 22:21
3
@alpha_989 If you want to access the method of a particular class only, you should reference that class directly rather than using super. Super is about following the chain of inheritance, not getting to a specific class's method.
– Zags
May 6 '18 at 12:04
Thanks for explicitly mentioning 'A class only appears once in the MRO'. This solved my problem. Now I finally understand how multiple inheritance works. Somebody needed to mention the properties of MRO!
– Tushar Vazirani
Nov 19 '18 at 20:25
add a comment |
Overall
Assuming everything descends from object
(you are on your own if it doesn't), Python computes a method resolution order (MRO) based on your class inheritance tree. The MRO satisfies 3 properties:
- Children of a class come before their parents
- Left parents come before right parents
- A class only appears once in the MRO
If no such ordering exists, Python errors. The inner workings of this is a C3 Linerization of the classes ancestry. Read all about it here: https://www.python.org/download/releases/2.3/mro/
Thus, in both of the examples below, it is:
- Child
- Left
- Right
- Parent
When a method is called, the first occurrence of that method in the MRO is the one that is called. Any class that doesn't implement that method is skipped. Any call to super
within that method will call the next occurrence of that method in the MRO. Consequently, it matters both what order you place classes in inheritance, and where you put the calls to super
in the methods.
With super
first in each method
class Parent(object):
def __init__(self):
super(Parent, self).__init__()
print "parent"
class Left(Parent):
def __init__(self):
super(Left, self).__init__()
print "left"
class Right(Parent):
def __init__(self):
super(Right, self).__init__()
print "right"
class Child(Left, Right):
def __init__(self):
super(Child, self).__init__()
print "child"
Child()
Outputs:
parent
right
left
child
With super
last in each method
class Parent(object):
def __init__(self):
print "parent"
super(Parent, self).__init__()
class Left(Parent):
def __init__(self):
print "left"
super(Left, self).__init__()
class Right(Parent):
def __init__(self):
print "right"
super(Right, self).__init__()
class Child(Left, Right):
def __init__(self):
print "child"
super(Child, self).__init__()
Child()
Outputs:
child
left
right
parent
Overall
Assuming everything descends from object
(you are on your own if it doesn't), Python computes a method resolution order (MRO) based on your class inheritance tree. The MRO satisfies 3 properties:
- Children of a class come before their parents
- Left parents come before right parents
- A class only appears once in the MRO
If no such ordering exists, Python errors. The inner workings of this is a C3 Linerization of the classes ancestry. Read all about it here: https://www.python.org/download/releases/2.3/mro/
Thus, in both of the examples below, it is:
- Child
- Left
- Right
- Parent
When a method is called, the first occurrence of that method in the MRO is the one that is called. Any class that doesn't implement that method is skipped. Any call to super
within that method will call the next occurrence of that method in the MRO. Consequently, it matters both what order you place classes in inheritance, and where you put the calls to super
in the methods.
With super
first in each method
class Parent(object):
def __init__(self):
super(Parent, self).__init__()
print "parent"
class Left(Parent):
def __init__(self):
super(Left, self).__init__()
print "left"
class Right(Parent):
def __init__(self):
super(Right, self).__init__()
print "right"
class Child(Left, Right):
def __init__(self):
super(Child, self).__init__()
print "child"
Child()
Outputs:
parent
right
left
child
With super
last in each method
class Parent(object):
def __init__(self):
print "parent"
super(Parent, self).__init__()
class Left(Parent):
def __init__(self):
print "left"
super(Left, self).__init__()
class Right(Parent):
def __init__(self):
print "right"
super(Right, self).__init__()
class Child(Left, Right):
def __init__(self):
print "child"
super(Child, self).__init__()
Child()
Outputs:
child
left
right
parent
edited Dec 13 '17 at 20:35
answered Sep 18 '17 at 18:44
ZagsZags
13k84884
13k84884
I see that you can accessLeft
usingsuper()
fromChild
. suppose I want to accessRight
from insideChild
. Is there a way to accessRight
fromChild
using super? Or should I directly calledRight
from insidesuper
?
– alpha_989
Apr 15 '18 at 22:21
3
@alpha_989 If you want to access the method of a particular class only, you should reference that class directly rather than using super. Super is about following the chain of inheritance, not getting to a specific class's method.
– Zags
May 6 '18 at 12:04
Thanks for explicitly mentioning 'A class only appears once in the MRO'. This solved my problem. Now I finally understand how multiple inheritance works. Somebody needed to mention the properties of MRO!
– Tushar Vazirani
Nov 19 '18 at 20:25
add a comment |
I see that you can accessLeft
usingsuper()
fromChild
. suppose I want to accessRight
from insideChild
. Is there a way to accessRight
fromChild
using super? Or should I directly calledRight
from insidesuper
?
– alpha_989
Apr 15 '18 at 22:21
3
@alpha_989 If you want to access the method of a particular class only, you should reference that class directly rather than using super. Super is about following the chain of inheritance, not getting to a specific class's method.
– Zags
May 6 '18 at 12:04
Thanks for explicitly mentioning 'A class only appears once in the MRO'. This solved my problem. Now I finally understand how multiple inheritance works. Somebody needed to mention the properties of MRO!
– Tushar Vazirani
Nov 19 '18 at 20:25
I see that you can access
Left
using super()
from Child
. suppose I want to access Right
from inside Child
. Is there a way to access Right
from Child
using super? Or should I directly called Right
from inside super
?– alpha_989
Apr 15 '18 at 22:21
I see that you can access
Left
using super()
from Child
. suppose I want to access Right
from inside Child
. Is there a way to access Right
from Child
using super? Or should I directly called Right
from inside super
?– alpha_989
Apr 15 '18 at 22:21
3
3
@alpha_989 If you want to access the method of a particular class only, you should reference that class directly rather than using super. Super is about following the chain of inheritance, not getting to a specific class's method.
– Zags
May 6 '18 at 12:04
@alpha_989 If you want to access the method of a particular class only, you should reference that class directly rather than using super. Super is about following the chain of inheritance, not getting to a specific class's method.
– Zags
May 6 '18 at 12:04
Thanks for explicitly mentioning 'A class only appears once in the MRO'. This solved my problem. Now I finally understand how multiple inheritance works. Somebody needed to mention the properties of MRO!
– Tushar Vazirani
Nov 19 '18 at 20:25
Thanks for explicitly mentioning 'A class only appears once in the MRO'. This solved my problem. Now I finally understand how multiple inheritance works. Somebody needed to mention the properties of MRO!
– Tushar Vazirani
Nov 19 '18 at 20:25
add a comment |
Another not yet covered point is passing parameters for initialization of classes. Since the destination of super
depends on the subclass the only good way to pass parameters is packing them all together. Then be careful to not have the same parameter name with different meanings.
Example:
class A(object):
def __init__(self, **kwargs):
print('A.__init__')
super().__init__()
class B(A):
def __init__(self, **kwargs):
print('B.__init__ {}'.format(kwargs['x']))
super().__init__(**kwargs)
class C(A):
def __init__(self, **kwargs):
print('C.__init__ with {}, {}'.format(kwargs['a'], kwargs['b']))
super().__init__(**kwargs)
class D(B, C): # MRO=D, B, C, A
def __init__(self):
print('D.__init__')
super().__init__(a=1, b=2, x=3)
print(D.mro())
D()
gives:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D.__init__
B.__init__ 3
C.__init__ with 1, 2
A.__init__
Calling the super class __init__
directly to more direct assignment of parameters is tempting but fails if there is any super
call in a super class and/or the MRO is changed and class A may be called multiple times, depending on the implementation.
To conclude: cooperative inheritance and super and specific parameters for initialization aren't working together very well.
add a comment |
Another not yet covered point is passing parameters for initialization of classes. Since the destination of super
depends on the subclass the only good way to pass parameters is packing them all together. Then be careful to not have the same parameter name with different meanings.
Example:
class A(object):
def __init__(self, **kwargs):
print('A.__init__')
super().__init__()
class B(A):
def __init__(self, **kwargs):
print('B.__init__ {}'.format(kwargs['x']))
super().__init__(**kwargs)
class C(A):
def __init__(self, **kwargs):
print('C.__init__ with {}, {}'.format(kwargs['a'], kwargs['b']))
super().__init__(**kwargs)
class D(B, C): # MRO=D, B, C, A
def __init__(self):
print('D.__init__')
super().__init__(a=1, b=2, x=3)
print(D.mro())
D()
gives:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D.__init__
B.__init__ 3
C.__init__ with 1, 2
A.__init__
Calling the super class __init__
directly to more direct assignment of parameters is tempting but fails if there is any super
call in a super class and/or the MRO is changed and class A may be called multiple times, depending on the implementation.
To conclude: cooperative inheritance and super and specific parameters for initialization aren't working together very well.
add a comment |
Another not yet covered point is passing parameters for initialization of classes. Since the destination of super
depends on the subclass the only good way to pass parameters is packing them all together. Then be careful to not have the same parameter name with different meanings.
Example:
class A(object):
def __init__(self, **kwargs):
print('A.__init__')
super().__init__()
class B(A):
def __init__(self, **kwargs):
print('B.__init__ {}'.format(kwargs['x']))
super().__init__(**kwargs)
class C(A):
def __init__(self, **kwargs):
print('C.__init__ with {}, {}'.format(kwargs['a'], kwargs['b']))
super().__init__(**kwargs)
class D(B, C): # MRO=D, B, C, A
def __init__(self):
print('D.__init__')
super().__init__(a=1, b=2, x=3)
print(D.mro())
D()
gives:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D.__init__
B.__init__ 3
C.__init__ with 1, 2
A.__init__
Calling the super class __init__
directly to more direct assignment of parameters is tempting but fails if there is any super
call in a super class and/or the MRO is changed and class A may be called multiple times, depending on the implementation.
To conclude: cooperative inheritance and super and specific parameters for initialization aren't working together very well.
Another not yet covered point is passing parameters for initialization of classes. Since the destination of super
depends on the subclass the only good way to pass parameters is packing them all together. Then be careful to not have the same parameter name with different meanings.
Example:
class A(object):
def __init__(self, **kwargs):
print('A.__init__')
super().__init__()
class B(A):
def __init__(self, **kwargs):
print('B.__init__ {}'.format(kwargs['x']))
super().__init__(**kwargs)
class C(A):
def __init__(self, **kwargs):
print('C.__init__ with {}, {}'.format(kwargs['a'], kwargs['b']))
super().__init__(**kwargs)
class D(B, C): # MRO=D, B, C, A
def __init__(self):
print('D.__init__')
super().__init__(a=1, b=2, x=3)
print(D.mro())
D()
gives:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D.__init__
B.__init__ 3
C.__init__ with 1, 2
A.__init__
Calling the super class __init__
directly to more direct assignment of parameters is tempting but fails if there is any super
call in a super class and/or the MRO is changed and class A may be called multiple times, depending on the implementation.
To conclude: cooperative inheritance and super and specific parameters for initialization aren't working together very well.
answered Jul 29 '14 at 11:57
TrilarionTrilarion
6,53753877
6,53753877
add a comment |
add a comment |
class First(object):
def __init__(self, a):
print "first", a
super(First, self).__init__(20)
class Second(object):
def __init__(self, a):
print "second", a
super(Second, self).__init__()
class Third(First, Second):
def __init__(self):
super(Third, self).__init__(10)
print "that's it"
t = Third()
Output is
first 10
second 20
that's it
Call to Third() locates the init defined in Third. And call to super in that routine invokes init defined in First. MRO=[First, Second].
Now call to super in init defined in First will continue searching MRO and find init defined in Second, and any call to super will hit the default object init. I hope this example clarifies the concept.
If you don't call super from First. The chain stops and you will get the following output.
first 10
that's it
1
that's because in class First, you called 'print' first then 'super'.
– rocky qi
Feb 25 '16 at 2:00
2
that was to illustrate the calling order
– Seraj Ahmad
Mar 6 '16 at 8:34
add a comment |
class First(object):
def __init__(self, a):
print "first", a
super(First, self).__init__(20)
class Second(object):
def __init__(self, a):
print "second", a
super(Second, self).__init__()
class Third(First, Second):
def __init__(self):
super(Third, self).__init__(10)
print "that's it"
t = Third()
Output is
first 10
second 20
that's it
Call to Third() locates the init defined in Third. And call to super in that routine invokes init defined in First. MRO=[First, Second].
Now call to super in init defined in First will continue searching MRO and find init defined in Second, and any call to super will hit the default object init. I hope this example clarifies the concept.
If you don't call super from First. The chain stops and you will get the following output.
first 10
that's it
1
that's because in class First, you called 'print' first then 'super'.
– rocky qi
Feb 25 '16 at 2:00
2
that was to illustrate the calling order
– Seraj Ahmad
Mar 6 '16 at 8:34
add a comment |
class First(object):
def __init__(self, a):
print "first", a
super(First, self).__init__(20)
class Second(object):
def __init__(self, a):
print "second", a
super(Second, self).__init__()
class Third(First, Second):
def __init__(self):
super(Third, self).__init__(10)
print "that's it"
t = Third()
Output is
first 10
second 20
that's it
Call to Third() locates the init defined in Third. And call to super in that routine invokes init defined in First. MRO=[First, Second].
Now call to super in init defined in First will continue searching MRO and find init defined in Second, and any call to super will hit the default object init. I hope this example clarifies the concept.
If you don't call super from First. The chain stops and you will get the following output.
first 10
that's it
class First(object):
def __init__(self, a):
print "first", a
super(First, self).__init__(20)
class Second(object):
def __init__(self, a):
print "second", a
super(Second, self).__init__()
class Third(First, Second):
def __init__(self):
super(Third, self).__init__(10)
print "that's it"
t = Third()
Output is
first 10
second 20
that's it
Call to Third() locates the init defined in Third. And call to super in that routine invokes init defined in First. MRO=[First, Second].
Now call to super in init defined in First will continue searching MRO and find init defined in Second, and any call to super will hit the default object init. I hope this example clarifies the concept.
If you don't call super from First. The chain stops and you will get the following output.
first 10
that's it
edited Nov 21 '16 at 2:23
answered Dec 10 '15 at 20:35
Seraj AhmadSeraj Ahmad
22117
22117
1
that's because in class First, you called 'print' first then 'super'.
– rocky qi
Feb 25 '16 at 2:00
2
that was to illustrate the calling order
– Seraj Ahmad
Mar 6 '16 at 8:34
add a comment |
1
that's because in class First, you called 'print' first then 'super'.
– rocky qi
Feb 25 '16 at 2:00
2
that was to illustrate the calling order
– Seraj Ahmad
Mar 6 '16 at 8:34
1
1
that's because in class First, you called 'print' first then 'super'.
– rocky qi
Feb 25 '16 at 2:00
that's because in class First, you called 'print' first then 'super'.
– rocky qi
Feb 25 '16 at 2:00
2
2
that was to illustrate the calling order
– Seraj Ahmad
Mar 6 '16 at 8:34
that was to illustrate the calling order
– Seraj Ahmad
Mar 6 '16 at 8:34
add a comment |
I would like to add to what @Visionscaper says at the top:
Third --> First --> object --> Second --> object
In this case the interpreter doesnt filter out the object class because its duplicated, rather its because Second appears in a head position and doesnt appear in the tail position in a hierarchy subset. While object only appears in tail positions and is not considered a strong position in C3 algorithm to determine priority.
The linearisation(mro) of a class C, L(C), is the
- the Class C
- plus the merge of
- linearisation of its parents P1, P2, .. = L(P1, P2, ...) and
- the list of its parents P1, P2, ..
Linearised Merge is done by selecting the common classes that appears as the head of lists and not the tail since order matters(will become clear below)
The linearisation of Third can be computed as follows:
L(O) := [O] // the linearization(mro) of O(object), because O has no parents
L(First) := [First] + merge(L(O), [O])
= [First] + merge([O], [O])
= [First, O]
// Similarly,
L(Second) := [Second, O]
L(Third) := [Third] + merge(L(First), L(Second), [First, Second])
= [Third] + merge([First, O], [Second, O], [First, Second])
// class First is a good candidate for the first merge step, because it only appears as the head of the first and last lists
// class O is not a good candidate for the next merge step, because it also appears in the tails of list 1 and 2,
= [Third, First] + merge([O], [Second, O], [Second])
// class Second is a good candidate for the second merge step, because it appears as the head of the list 2 and 3
= [Third, First, Second] + merge([O], [O])
= [Third, First, Second, O]
Thus for a super() implementation in the following 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
it becomes obvious how this method will be resolved
Third.__init__() ---> First.__init__() ---> Second.__init__() --->
Object.__init__() ---> returns ---> Second.__init__() -
prints "second" - returns ---> First.__init__() -
prints "first" - returns ---> Third.__init__() - prints "that's it"
"rather its because Second appears in a head position and doesn't appear in the tail position in a hierarchy subset." It's not clear what a head or tail position is, nor what a hierarchy subset is or which subset you are referring to.
– OrangeSherbet
Jul 18 '17 at 21:37
Tail position refers to classes that are higher in the class hierarchy and vice versa. The base class 'object' is at the end of the tail. The key to understanding the mro algorithm is how 'Second' appears as the super of 'First'. We would normally assume it to be the 'object' class. Thats true, but, only in the perspective of the 'First' class. However when viewed from the 'Third' class perspective, the hierarchy order for 'First' is different and is calculated as shown above. mro algorithm tries to create this perspective(or hierarchy subset) for all multiple inherited classes
– supi
Jul 22 '17 at 13:05
add a comment |
I would like to add to what @Visionscaper says at the top:
Third --> First --> object --> Second --> object
In this case the interpreter doesnt filter out the object class because its duplicated, rather its because Second appears in a head position and doesnt appear in the tail position in a hierarchy subset. While object only appears in tail positions and is not considered a strong position in C3 algorithm to determine priority.
The linearisation(mro) of a class C, L(C), is the
- the Class C
- plus the merge of
- linearisation of its parents P1, P2, .. = L(P1, P2, ...) and
- the list of its parents P1, P2, ..
Linearised Merge is done by selecting the common classes that appears as the head of lists and not the tail since order matters(will become clear below)
The linearisation of Third can be computed as follows:
L(O) := [O] // the linearization(mro) of O(object), because O has no parents
L(First) := [First] + merge(L(O), [O])
= [First] + merge([O], [O])
= [First, O]
// Similarly,
L(Second) := [Second, O]
L(Third) := [Third] + merge(L(First), L(Second), [First, Second])
= [Third] + merge([First, O], [Second, O], [First, Second])
// class First is a good candidate for the first merge step, because it only appears as the head of the first and last lists
// class O is not a good candidate for the next merge step, because it also appears in the tails of list 1 and 2,
= [Third, First] + merge([O], [Second, O], [Second])
// class Second is a good candidate for the second merge step, because it appears as the head of the list 2 and 3
= [Third, First, Second] + merge([O], [O])
= [Third, First, Second, O]
Thus for a super() implementation in the following 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
it becomes obvious how this method will be resolved
Third.__init__() ---> First.__init__() ---> Second.__init__() --->
Object.__init__() ---> returns ---> Second.__init__() -
prints "second" - returns ---> First.__init__() -
prints "first" - returns ---> Third.__init__() - prints "that's it"
"rather its because Second appears in a head position and doesn't appear in the tail position in a hierarchy subset." It's not clear what a head or tail position is, nor what a hierarchy subset is or which subset you are referring to.
– OrangeSherbet
Jul 18 '17 at 21:37
Tail position refers to classes that are higher in the class hierarchy and vice versa. The base class 'object' is at the end of the tail. The key to understanding the mro algorithm is how 'Second' appears as the super of 'First'. We would normally assume it to be the 'object' class. Thats true, but, only in the perspective of the 'First' class. However when viewed from the 'Third' class perspective, the hierarchy order for 'First' is different and is calculated as shown above. mro algorithm tries to create this perspective(or hierarchy subset) for all multiple inherited classes
– supi
Jul 22 '17 at 13:05
add a comment |
I would like to add to what @Visionscaper says at the top:
Third --> First --> object --> Second --> object
In this case the interpreter doesnt filter out the object class because its duplicated, rather its because Second appears in a head position and doesnt appear in the tail position in a hierarchy subset. While object only appears in tail positions and is not considered a strong position in C3 algorithm to determine priority.
The linearisation(mro) of a class C, L(C), is the
- the Class C
- plus the merge of
- linearisation of its parents P1, P2, .. = L(P1, P2, ...) and
- the list of its parents P1, P2, ..
Linearised Merge is done by selecting the common classes that appears as the head of lists and not the tail since order matters(will become clear below)
The linearisation of Third can be computed as follows:
L(O) := [O] // the linearization(mro) of O(object), because O has no parents
L(First) := [First] + merge(L(O), [O])
= [First] + merge([O], [O])
= [First, O]
// Similarly,
L(Second) := [Second, O]
L(Third) := [Third] + merge(L(First), L(Second), [First, Second])
= [Third] + merge([First, O], [Second, O], [First, Second])
// class First is a good candidate for the first merge step, because it only appears as the head of the first and last lists
// class O is not a good candidate for the next merge step, because it also appears in the tails of list 1 and 2,
= [Third, First] + merge([O], [Second, O], [Second])
// class Second is a good candidate for the second merge step, because it appears as the head of the list 2 and 3
= [Third, First, Second] + merge([O], [O])
= [Third, First, Second, O]
Thus for a super() implementation in the following 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
it becomes obvious how this method will be resolved
Third.__init__() ---> First.__init__() ---> Second.__init__() --->
Object.__init__() ---> returns ---> Second.__init__() -
prints "second" - returns ---> First.__init__() -
prints "first" - returns ---> Third.__init__() - prints "that's it"
I would like to add to what @Visionscaper says at the top:
Third --> First --> object --> Second --> object
In this case the interpreter doesnt filter out the object class because its duplicated, rather its because Second appears in a head position and doesnt appear in the tail position in a hierarchy subset. While object only appears in tail positions and is not considered a strong position in C3 algorithm to determine priority.
The linearisation(mro) of a class C, L(C), is the
- the Class C
- plus the merge of
- linearisation of its parents P1, P2, .. = L(P1, P2, ...) and
- the list of its parents P1, P2, ..
Linearised Merge is done by selecting the common classes that appears as the head of lists and not the tail since order matters(will become clear below)
The linearisation of Third can be computed as follows:
L(O) := [O] // the linearization(mro) of O(object), because O has no parents
L(First) := [First] + merge(L(O), [O])
= [First] + merge([O], [O])
= [First, O]
// Similarly,
L(Second) := [Second, O]
L(Third) := [Third] + merge(L(First), L(Second), [First, Second])
= [Third] + merge([First, O], [Second, O], [First, Second])
// class First is a good candidate for the first merge step, because it only appears as the head of the first and last lists
// class O is not a good candidate for the next merge step, because it also appears in the tails of list 1 and 2,
= [Third, First] + merge([O], [Second, O], [Second])
// class Second is a good candidate for the second merge step, because it appears as the head of the list 2 and 3
= [Third, First, Second] + merge([O], [O])
= [Third, First, Second, O]
Thus for a super() implementation in the following 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(First, Second):
def __init__(self):
super(Third, self).__init__()
print "that's it"
it becomes obvious how this method will be resolved
Third.__init__() ---> First.__init__() ---> Second.__init__() --->
Object.__init__() ---> returns ---> Second.__init__() -
prints "second" - returns ---> First.__init__() -
prints "first" - returns ---> Third.__init__() - prints "that's it"
edited Jun 10 '18 at 11:16
Md. Abu Nafee Ibna Zahid
4031515
4031515
answered Sep 18 '16 at 13:41
supisupi
38337
38337
"rather its because Second appears in a head position and doesn't appear in the tail position in a hierarchy subset." It's not clear what a head or tail position is, nor what a hierarchy subset is or which subset you are referring to.
– OrangeSherbet
Jul 18 '17 at 21:37
Tail position refers to classes that are higher in the class hierarchy and vice versa. The base class 'object' is at the end of the tail. The key to understanding the mro algorithm is how 'Second' appears as the super of 'First'. We would normally assume it to be the 'object' class. Thats true, but, only in the perspective of the 'First' class. However when viewed from the 'Third' class perspective, the hierarchy order for 'First' is different and is calculated as shown above. mro algorithm tries to create this perspective(or hierarchy subset) for all multiple inherited classes
– supi
Jul 22 '17 at 13:05
add a comment |
"rather its because Second appears in a head position and doesn't appear in the tail position in a hierarchy subset." It's not clear what a head or tail position is, nor what a hierarchy subset is or which subset you are referring to.
– OrangeSherbet
Jul 18 '17 at 21:37
Tail position refers to classes that are higher in the class hierarchy and vice versa. The base class 'object' is at the end of the tail. The key to understanding the mro algorithm is how 'Second' appears as the super of 'First'. We would normally assume it to be the 'object' class. Thats true, but, only in the perspective of the 'First' class. However when viewed from the 'Third' class perspective, the hierarchy order for 'First' is different and is calculated as shown above. mro algorithm tries to create this perspective(or hierarchy subset) for all multiple inherited classes
– supi
Jul 22 '17 at 13:05
"rather its because Second appears in a head position and doesn't appear in the tail position in a hierarchy subset." It's not clear what a head or tail position is, nor what a hierarchy subset is or which subset you are referring to.
– OrangeSherbet
Jul 18 '17 at 21:37
"rather its because Second appears in a head position and doesn't appear in the tail position in a hierarchy subset." It's not clear what a head or tail position is, nor what a hierarchy subset is or which subset you are referring to.
– OrangeSherbet
Jul 18 '17 at 21:37
Tail position refers to classes that are higher in the class hierarchy and vice versa. The base class 'object' is at the end of the tail. The key to understanding the mro algorithm is how 'Second' appears as the super of 'First'. We would normally assume it to be the 'object' class. Thats true, but, only in the perspective of the 'First' class. However when viewed from the 'Third' class perspective, the hierarchy order for 'First' is different and is calculated as shown above. mro algorithm tries to create this perspective(or hierarchy subset) for all multiple inherited classes
– supi
Jul 22 '17 at 13:05
Tail position refers to classes that are higher in the class hierarchy and vice versa. The base class 'object' is at the end of the tail. The key to understanding the mro algorithm is how 'Second' appears as the super of 'First'. We would normally assume it to be the 'object' class. Thats true, but, only in the perspective of the 'First' class. However when viewed from the 'Third' class perspective, the hierarchy order for 'First' is different and is calculated as shown above. mro algorithm tries to create this perspective(or hierarchy subset) for all multiple inherited classes
– supi
Jul 22 '17 at 13:05
add a comment |
In learningpythonthehardway I learn something called super() an in-built function if not mistaken. Calling super() function can help the inheritance to pass through the parent and 'siblings' and help you to see clearer. I am still a beginner but I love to share my experience on using this super() in python2.7.
If you have read through the comments in this page, you will heard of Method Resolution Order (MRO), method being the function you wrote, MRO will be using Depth-First-Left-to-Right scheme to search and run. You can do more research on that.
By adding super() function
super(First, self).__init__() #example for class First.
You can connect multiple instances and 'families' with super(), by adding in each and every one in them. And it will execute the methods, go through them and make sure you didn't miss out! However adding them before or after does make difference you will know if you have done the learningpythonthehardway exercise 44. Let the fun begins!!
Taking example below, you can copy & paste and try run it:
class First(object):
def __init__(self):
print("first")
class Second(First):
def __init__(self):
print("second (before)")
super(Second, self).__init__()
print("second (after)")
class Third(First):
def __init__(self):
print("third (before)")
super(Third, self).__init__()
print("third (after)")
class Fourth(First):
def __init__(self):
print("fourth (before)")
super(Fourth, self).__init__()
print("fourth (after)")
class Fifth(Second, Third, Fourth):
def __init__(self):
print("fifth (before)")
super(Fifth, self).__init__()
print("fifth (after)")
Fifth()
How does it run? Instance of fifth() will goes like this. Each steps goes from class to class where the super function added.
1.) print("fifth (before)")
2.) super()>[Second, Third, Fourth] (Left to right)
3.) print("second (before)")
4.) super()> First (First is the Parent which inherit from object)
Parent was found and it will goes continue to Third and Fourth!!
5.) print("third (before)")
6.) super()> First (Parent class)
7.) print ("Fourth (before)")
8.) super()> First (Parent class)
Now all the classes with super() has been accessed! The parent class has been found and executed and now it continues to un-box the function in the inheritances to finished the codes.
9.) print("first") (Parent)
10.) print ("Fourth (after)") (Class Fourth un-box)
11.) print("third (after)") (Class Third un-box)
12.) print("second (after)") (Class Second un-box)
13.) print("fifth (after)") (Class Fifth un-box)
14.) Fifth() executed
The outcome of the program above:
fifth (before)
second (before
third (before)
fourth (before)
first
fourth (after)
third (after)
second (after)
fifth (after)
For me by adding super() allows me to see clearer on how python would execute my coding and make sure the inheritance can access the method I intended.
Thanks for the detailed demo!
– Tushar Vazirani
Nov 19 '18 at 20:29
add a comment |
In learningpythonthehardway I learn something called super() an in-built function if not mistaken. Calling super() function can help the inheritance to pass through the parent and 'siblings' and help you to see clearer. I am still a beginner but I love to share my experience on using this super() in python2.7.
If you have read through the comments in this page, you will heard of Method Resolution Order (MRO), method being the function you wrote, MRO will be using Depth-First-Left-to-Right scheme to search and run. You can do more research on that.
By adding super() function
super(First, self).__init__() #example for class First.
You can connect multiple instances and 'families' with super(), by adding in each and every one in them. And it will execute the methods, go through them and make sure you didn't miss out! However adding them before or after does make difference you will know if you have done the learningpythonthehardway exercise 44. Let the fun begins!!
Taking example below, you can copy & paste and try run it:
class First(object):
def __init__(self):
print("first")
class Second(First):
def __init__(self):
print("second (before)")
super(Second, self).__init__()
print("second (after)")
class Third(First):
def __init__(self):
print("third (before)")
super(Third, self).__init__()
print("third (after)")
class Fourth(First):
def __init__(self):
print("fourth (before)")
super(Fourth, self).__init__()
print("fourth (after)")
class Fifth(Second, Third, Fourth):
def __init__(self):
print("fifth (before)")
super(Fifth, self).__init__()
print("fifth (after)")
Fifth()
How does it run? Instance of fifth() will goes like this. Each steps goes from class to class where the super function added.
1.) print("fifth (before)")
2.) super()>[Second, Third, Fourth] (Left to right)
3.) print("second (before)")
4.) super()> First (First is the Parent which inherit from object)
Parent was found and it will goes continue to Third and Fourth!!
5.) print("third (before)")
6.) super()> First (Parent class)
7.) print ("Fourth (before)")
8.) super()> First (Parent class)
Now all the classes with super() has been accessed! The parent class has been found and executed and now it continues to un-box the function in the inheritances to finished the codes.
9.) print("first") (Parent)
10.) print ("Fourth (after)") (Class Fourth un-box)
11.) print("third (after)") (Class Third un-box)
12.) print("second (after)") (Class Second un-box)
13.) print("fifth (after)") (Class Fifth un-box)
14.) Fifth() executed
The outcome of the program above:
fifth (before)
second (before
third (before)
fourth (before)
first
fourth (after)
third (after)
second (after)
fifth (after)
For me by adding super() allows me to see clearer on how python would execute my coding and make sure the inheritance can access the method I intended.
Thanks for the detailed demo!
– Tushar Vazirani
Nov 19 '18 at 20:29
add a comment |
In learningpythonthehardway I learn something called super() an in-built function if not mistaken. Calling super() function can help the inheritance to pass through the parent and 'siblings' and help you to see clearer. I am still a beginner but I love to share my experience on using this super() in python2.7.
If you have read through the comments in this page, you will heard of Method Resolution Order (MRO), method being the function you wrote, MRO will be using Depth-First-Left-to-Right scheme to search and run. You can do more research on that.
By adding super() function
super(First, self).__init__() #example for class First.
You can connect multiple instances and 'families' with super(), by adding in each and every one in them. And it will execute the methods, go through them and make sure you didn't miss out! However adding them before or after does make difference you will know if you have done the learningpythonthehardway exercise 44. Let the fun begins!!
Taking example below, you can copy & paste and try run it:
class First(object):
def __init__(self):
print("first")
class Second(First):
def __init__(self):
print("second (before)")
super(Second, self).__init__()
print("second (after)")
class Third(First):
def __init__(self):
print("third (before)")
super(Third, self).__init__()
print("third (after)")
class Fourth(First):
def __init__(self):
print("fourth (before)")
super(Fourth, self).__init__()
print("fourth (after)")
class Fifth(Second, Third, Fourth):
def __init__(self):
print("fifth (before)")
super(Fifth, self).__init__()
print("fifth (after)")
Fifth()
How does it run? Instance of fifth() will goes like this. Each steps goes from class to class where the super function added.
1.) print("fifth (before)")
2.) super()>[Second, Third, Fourth] (Left to right)
3.) print("second (before)")
4.) super()> First (First is the Parent which inherit from object)
Parent was found and it will goes continue to Third and Fourth!!
5.) print("third (before)")
6.) super()> First (Parent class)
7.) print ("Fourth (before)")
8.) super()> First (Parent class)
Now all the classes with super() has been accessed! The parent class has been found and executed and now it continues to un-box the function in the inheritances to finished the codes.
9.) print("first") (Parent)
10.) print ("Fourth (after)") (Class Fourth un-box)
11.) print("third (after)") (Class Third un-box)
12.) print("second (after)") (Class Second un-box)
13.) print("fifth (after)") (Class Fifth un-box)
14.) Fifth() executed
The outcome of the program above:
fifth (before)
second (before
third (before)
fourth (before)
first
fourth (after)
third (after)
second (after)
fifth (after)
For me by adding super() allows me to see clearer on how python would execute my coding and make sure the inheritance can access the method I intended.
In learningpythonthehardway I learn something called super() an in-built function if not mistaken. Calling super() function can help the inheritance to pass through the parent and 'siblings' and help you to see clearer. I am still a beginner but I love to share my experience on using this super() in python2.7.
If you have read through the comments in this page, you will heard of Method Resolution Order (MRO), method being the function you wrote, MRO will be using Depth-First-Left-to-Right scheme to search and run. You can do more research on that.
By adding super() function
super(First, self).__init__() #example for class First.
You can connect multiple instances and 'families' with super(), by adding in each and every one in them. And it will execute the methods, go through them and make sure you didn't miss out! However adding them before or after does make difference you will know if you have done the learningpythonthehardway exercise 44. Let the fun begins!!
Taking example below, you can copy & paste and try run it:
class First(object):
def __init__(self):
print("first")
class Second(First):
def __init__(self):
print("second (before)")
super(Second, self).__init__()
print("second (after)")
class Third(First):
def __init__(self):
print("third (before)")
super(Third, self).__init__()
print("third (after)")
class Fourth(First):
def __init__(self):
print("fourth (before)")
super(Fourth, self).__init__()
print("fourth (after)")
class Fifth(Second, Third, Fourth):
def __init__(self):
print("fifth (before)")
super(Fifth, self).__init__()
print("fifth (after)")
Fifth()
How does it run? Instance of fifth() will goes like this. Each steps goes from class to class where the super function added.
1.) print("fifth (before)")
2.) super()>[Second, Third, Fourth] (Left to right)
3.) print("second (before)")
4.) super()> First (First is the Parent which inherit from object)
Parent was found and it will goes continue to Third and Fourth!!
5.) print("third (before)")
6.) super()> First (Parent class)
7.) print ("Fourth (before)")
8.) super()> First (Parent class)
Now all the classes with super() has been accessed! The parent class has been found and executed and now it continues to un-box the function in the inheritances to finished the codes.
9.) print("first") (Parent)
10.) print ("Fourth (after)") (Class Fourth un-box)
11.) print("third (after)") (Class Third un-box)
12.) print("second (after)") (Class Second un-box)
13.) print("fifth (after)") (Class Fifth un-box)
14.) Fifth() executed
The outcome of the program above:
fifth (before)
second (before
third (before)
fourth (before)
first
fourth (after)
third (after)
second (after)
fifth (after)
For me by adding super() allows me to see clearer on how python would execute my coding and make sure the inheritance can access the method I intended.
edited Nov 13 '18 at 7:32
lagom
3,47181937
3,47181937
answered Nov 13 '18 at 7:12
Will MeetYouWill MeetYou
237
237
Thanks for the detailed demo!
– Tushar Vazirani
Nov 19 '18 at 20:29
add a comment |
Thanks for the detailed demo!
– Tushar Vazirani
Nov 19 '18 at 20:29
Thanks for the detailed demo!
– Tushar Vazirani
Nov 19 '18 at 20:29
Thanks for the detailed demo!
– Tushar Vazirani
Nov 19 '18 at 20:29
add a comment |
protected by Community♦ Dec 9 '16 at 17:53
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
In fact, multiple inheritance is the only case where
super()
is of any use. I would not recommend using it with classes using linear inheritance, where it's just useless overhead.– Bachsau
Apr 15 '18 at 21:56
@Bachsau is technically correct in that it is a small overhead but super() is more pythonic and allows for re-factoring and changes to the code over time. Use super() unless you really need a named class specific method.
– Paul Whipp
Nov 18 '18 at 19:55
1
Another problem with
super()
is, that it forces every subclass to use it as well, while when not usingsuper()
, everyone subclassing it can decide himself. If a developer using it doesn't know aboutsuper()
or doesn't know it was used, problems with the mro can arise that are very hard to track down.– Bachsau
Nov 30 '18 at 13:37