How does Python's super() work with multiple inheritance?












675














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).










share|improve this question
























  • 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 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
















675














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).










share|improve this question
























  • 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 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














675












675








675


271





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).










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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 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


















  • 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 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
















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












12 Answers
12






active

oldest

votes


















560














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'>)





share|improve this answer



















  • 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





















198














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





share|improve this answer



















  • 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... 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





















137














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().




  1. According to MRO __init__ of Third is called first.


  2. Next, according to the MRO, inside the __init__ method super(Third,
    self).__init__()
    resolves to the __init__ method of First, which
    gets called.


  3. Inside __init__ of First super(First, self).__init__() calls the __init__ of Second, because that is what the MRO dictates!


  4. Inside __init__ of Second super(Second, self).__init__() calls
    the __init__ of object, which amounts to nothing. After that
    "second" is printed.


  5. After super(First, self).__init__() completed,
    "first" is printed.


  6. 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!






share|improve this answer



















  • 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: 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




    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



















46














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.






share|improve this answer























  • 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



















25














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)





share|improve this answer





















  • 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 using args / kwargs rather than named parameters.
    – max
    Jun 11 '17 at 23:00





















18














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.






share|improve this answer



















  • 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












  • @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



















14














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'.






share|improve this answer





















  • 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



















13














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:




  1. Child

  2. Left

  3. Right

  4. 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





share|improve this answer























  • 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




    @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





















11














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.






share|improve this answer





























    4














    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





    share|improve this answer



















    • 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



















    2














    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"





    share|improve this answer























    • "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





















    1














    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.






    share|improve this answer























    • Thanks for the detailed demo!
      – Tushar Vazirani
      Nov 19 '18 at 20:29










    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









    560














    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'>)





    share|improve this answer



















    • 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


















    560














    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'>)





    share|improve this answer



















    • 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
















    560












    560








    560






    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'>)





    share|improve this answer














    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'>)






    share|improve this answer














    share|improve this answer



    share|improve this answer








    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
















    • 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















    198














    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





    share|improve this answer



















    • 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... 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


















    198














    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





    share|improve this answer



















    • 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... 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
















    198












    198








    198






    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





    share|improve this answer














    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






    share|improve this answer














    share|improve this answer



    share|improve this answer








    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... 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
















    • 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... 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










    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













    137














    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().




    1. According to MRO __init__ of Third is called first.


    2. Next, according to the MRO, inside the __init__ method super(Third,
      self).__init__()
      resolves to the __init__ method of First, which
      gets called.


    3. Inside __init__ of First super(First, self).__init__() calls the __init__ of Second, because that is what the MRO dictates!


    4. Inside __init__ of Second super(Second, self).__init__() calls
      the __init__ of object, which amounts to nothing. After that
      "second" is printed.


    5. After super(First, self).__init__() completed,
      "first" is printed.


    6. 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!






    share|improve this answer



















    • 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: 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




      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
















    137














    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().




    1. According to MRO __init__ of Third is called first.


    2. Next, according to the MRO, inside the __init__ method super(Third,
      self).__init__()
      resolves to the __init__ method of First, which
      gets called.


    3. Inside __init__ of First super(First, self).__init__() calls the __init__ of Second, because that is what the MRO dictates!


    4. Inside __init__ of Second super(Second, self).__init__() calls
      the __init__ of object, which amounts to nothing. After that
      "second" is printed.


    5. After super(First, self).__init__() completed,
      "first" is printed.


    6. 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!






    share|improve this answer



















    • 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: 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




      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














    137












    137








    137






    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().




    1. According to MRO __init__ of Third is called first.


    2. Next, according to the MRO, inside the __init__ method super(Third,
      self).__init__()
      resolves to the __init__ method of First, which
      gets called.


    3. Inside __init__ of First super(First, self).__init__() calls the __init__ of Second, because that is what the MRO dictates!


    4. Inside __init__ of Second super(Second, self).__init__() calls
      the __init__ of object, which amounts to nothing. After that
      "second" is printed.


    5. After super(First, self).__init__() completed,
      "first" is printed.


    6. 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!






    share|improve this answer














    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().




    1. According to MRO __init__ of Third is called first.


    2. Next, according to the MRO, inside the __init__ method super(Third,
      self).__init__()
      resolves to the __init__ method of First, which
      gets called.


    3. Inside __init__ of First super(First, self).__init__() calls the __init__ of Second, because that is what the MRO dictates!


    4. Inside __init__ of Second super(Second, self).__init__() calls
      the __init__ of object, which amounts to nothing. After that
      "second" is printed.


    5. After super(First, self).__init__() completed,
      "first" is printed.


    6. 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!







    share|improve this answer














    share|improve this answer



    share|improve this answer








    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: 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




      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














    • 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: 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




      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








    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











    46














    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.






    share|improve this answer























    • 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
















    46














    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.






    share|improve this answer























    • 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














    46












    46








    46






    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.






    share|improve this answer














    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    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


















    • 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











    25














    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)





    share|improve this answer





















    • 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 using args / kwargs rather than named parameters.
      – max
      Jun 11 '17 at 23:00


















    25














    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)





    share|improve this answer





















    • 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 using args / kwargs rather than named parameters.
      – max
      Jun 11 '17 at 23:00
















    25












    25








    25






    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)





    share|improve this answer












    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)






    share|improve this answer












    share|improve this answer



    share|improve this answer










    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 using args / 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






    • 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 using args / 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













    18














    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.






    share|improve this answer



















    • 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












    • @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
















    18














    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.






    share|improve this answer



















    • 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












    • @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














    18












    18








    18






    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.






    share|improve this answer














    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    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 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










    • Unfortunately, this breaks if init tries to access any private methods :(
      – Erik Aronesty
      May 10 '18 at 21:29














    • 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












    • @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








    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











    14














    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'.






    share|improve this answer





















    • 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
















    14














    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'.






    share|improve this answer





















    • 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














    14












    14








    14






    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'.






    share|improve this answer












    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'.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    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


















    • 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











    13














    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:




    1. Child

    2. Left

    3. Right

    4. 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





    share|improve this answer























    • 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




      @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


















    13














    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:




    1. Child

    2. Left

    3. Right

    4. 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





    share|improve this answer























    • 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




      @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
















    13












    13








    13






    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:




    1. Child

    2. Left

    3. Right

    4. 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





    share|improve this answer














    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:




    1. Child

    2. Left

    3. Right

    4. 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






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Dec 13 '17 at 20:35

























    answered Sep 18 '17 at 18:44









    ZagsZags

    13k84884




    13k84884












    • 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




      @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






    • 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













    11














    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.






    share|improve this answer


























      11














      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.






      share|improve this answer
























        11












        11








        11






        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.






        share|improve this answer












        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jul 29 '14 at 11:57









        TrilarionTrilarion

        6,53753877




        6,53753877























            4














            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





            share|improve this answer



















            • 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
















            4














            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





            share|improve this answer



















            • 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














            4












            4








            4






            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





            share|improve this answer














            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






            share|improve this answer














            share|improve this answer



            share|improve this answer








            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














            • 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











            2














            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"





            share|improve this answer























            • "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


















            2














            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"





            share|improve this answer























            • "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
















            2












            2








            2






            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"





            share|improve this answer














            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"






            share|improve this answer














            share|improve this answer



            share|improve this answer








            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




















            • "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













            1














            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.






            share|improve this answer























            • Thanks for the detailed demo!
              – Tushar Vazirani
              Nov 19 '18 at 20:29
















            1














            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.






            share|improve this answer























            • Thanks for the detailed demo!
              – Tushar Vazirani
              Nov 19 '18 at 20:29














            1












            1








            1






            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.






            share|improve this answer














            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.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            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


















            • 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





            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?



            Popular posts from this blog

            Xamarin.iOS Cant Deploy on Iphone

            Glorious Revolution

            Dulmage-Mendelsohn matrix decomposition in Python