From: Lacrima on
Hi!

I have two super classes:

class SuperClass1(object):
def __init__(self, word):
print word

class SuperClass2(object):
def __init__(self, word, word2):
print word, word2

Also I have subclass of these classes:

class SubClass(SuperClass1, SuperClass2):
def __init__(self):
pass

I have two questions.
1) Inside __init__ of SubClass how can I firstly call __init__ of
SuperClass1, and then __init__ of SuperClass2, using builtin super()
function.
2) Why should I use super() at all, if it is very easy to call methods
of super class like this:
class SubClass(SuperClass1, SuperClass2):
def __init__(self):
SuperClass1.__init__(self, 'Python')
SuperClass2.__init__(self, 'Hello', 'world')

Thanks in advance.
From: Raymond Hettinger on
On Jul 24, 12:47 am, Lacrima <lacrima.ma...(a)gmail.com> wrote:
> Hi!
>
> I have two super classes:
>
> class SuperClass1(object):
>     def __init__(self, word):
>         print word
>
> class SuperClass2(object):
>     def __init__(self, word, word2):
>         print word, word2
>
> Also I have subclass of these classes:
>
> class SubClass(SuperClass1, SuperClass2):
>     def __init__(self):
>         pass
>
> I have two questions.
> 1) Inside __init__ of SubClass how can I firstly call __init__ of
> SuperClass1, and then __init__ of SuperClass2, using builtin super()
> function.

I would write it like this:


class SuperClass1(object):
def __init__(self, **kwds):
word = kwds.pop('word')
print word
super(SuperClass1, self).__init__(**kwds)

class SuperClass2(object):
def __init__(self, **kwds):
word1 = kwds.pop('word1')
word2 = kwds.pop('word2')
print word1, word2
super(SuperClass2, self).__init__(**kwds)

class SubClass(SuperClass1, SuperClass2):
def __init__(self, **kwds):
super(SubClass, self).__init__(**kwds)

SubClass(word='Python', word1='Hello', word2='World')




> 2) Why should I use super() at all, if it is very easy to call methods
> of super class like this:
> class SubClass(SuperClass1, SuperClass2):
>     def __init__(self):
>         SuperClass1.__init__(self, 'Python')
>         SuperClass2.__init__(self, 'Hello', 'world')

That works just fine in this case.
The challenge arises in "diamond diagrams"
such as A->B A->C B->D C->D where both B and C
are written independently of D and both need to call
A's __init__ but that method should only be called
once (not once by B and again by C).

In that case, the super() pattern shown above will
let each parent's method be called exactly once
and guarantee that parents are called before grandparents
and guarantee that the left-to-right ordering of multiple
bases is respected.


Raymond

From: Lacrima on
On Jul 24, 11:20 am, Raymond Hettinger <raymond.hettin...(a)gmail.com>
wrote:
> On Jul 24, 12:47 am, Lacrima <lacrima.ma...(a)gmail.com> wrote:
>
>
>
> > Hi!
>
> > I have two super classes:
>
> > class SuperClass1(object):
> >     def __init__(self, word):
> >         print word
>
> > class SuperClass2(object):
> >     def __init__(self, word, word2):
> >         print word, word2
>
> > Also I have subclass of these classes:
>
> > class SubClass(SuperClass1, SuperClass2):
> >     def __init__(self):
> >         pass
>
> > I have two questions.
> > 1) Inside __init__ of SubClass how can I firstly call __init__ of
> > SuperClass1, and then __init__ of SuperClass2, using builtin super()
> > function.
>
> I would write it like this:
>
> class SuperClass1(object):
>     def __init__(self, **kwds):
>         word = kwds.pop('word')
>         print word
>         super(SuperClass1, self).__init__(**kwds)
>
> class SuperClass2(object):
>     def __init__(self, **kwds):
>         word1 = kwds.pop('word1')
>         word2 = kwds.pop('word2')
>         print word1, word2
>         super(SuperClass2, self).__init__(**kwds)
>
> class SubClass(SuperClass1, SuperClass2):
>     def __init__(self, **kwds):
>         super(SubClass, self).__init__(**kwds)
>
> SubClass(word='Python', word1='Hello', word2='World')
>
> > 2) Why should I use super() at all, if it is very easy to call methods
> > of super class like this:
> > class SubClass(SuperClass1, SuperClass2):
> >     def __init__(self):
> >         SuperClass1.__init__(self, 'Python')
> >         SuperClass2.__init__(self, 'Hello', 'world')
>
> That works just fine in this case.
> The challenge arises in "diamond diagrams"
> such as A->B  A->C  B->D  C->D where both B and C
> are written independently of D and both need to call
> A's __init__ but that method should only be called
> once (not once by B and again by C).
>
> In that case, the super() pattern shown above will
> let each parent's method be called exactly once
> and guarantee that parents are called before grandparents
> and guarantee that the left-to-right ordering of multiple
> bases is respected.
>
> Raymond

Hi, Raymond!

Thank you for your answer.

Some things are still not clear. Your example works great. But if I
remove "super(SuperClass1, self).__init__(**kwds)" from SuperClass1's
__init__, the example stops working. That is when I instantiate
SubClass only __init__ of SuperClass1 is called and __init__ of
SuperClass2 is omitted, i.e. only 'Python' is printed. Why is it so?

So as I understand every parent should necessarily call super() at the
end of its __init__ method in order for things to work properly.

But what if SuperClass1 is from third party library? Then I can't
modify it to follow this convention, that is when I instantiate my
SubClass only __init__ from SuperClass1 will be called, and __init__
from SuperClass2 will be omitted.
How to deal with that?

My post is quite intricate, but this is because of my English. Sorry.

Looking forward for help. Thank you.
From: Raymond Hettinger on
On Jul 24, 3:56 am, Lacrima <lacrima.ma...(a)gmail.com> wrote:
> Thank you for your answer.

You're welcome.

> Some things are still not clear. Your example works great. But if I
> remove "super(SuperClass1, self).__init__(**kwds)" from SuperClass1's
> __init__, the example stops working. That is when I instantiate
> SubClass only __init__ of SuperClass1 is called and __init__ of
> SuperClass2 is omitted, i.e. only 'Python' is printed. Why is it so?
>
> So as I understand every parent should necessarily call super() at the
> end of its __init__ method in order for things to work properly.

Yes. That's correct. Python's super() was designed to support
cooperative multiple inheritance. The "cooperative" part means that
every class implementing the target method (such as __init__ in your
example) needs to call super() in order to trigger the next method in
the sequence (the method resolution order or MRO).


> But what if SuperClass1 is from third party library?
. . .
> How to deal with that?

Then, the odds are that that class isn't "cooperating". You can
either wrap the third-party library to add a super() call or you can
switch to an alternate design using composition instead of
inheritance.


Raymond


P.S. Outside of the simple case of single inheritance, the one key to
understanding super() is to forget about the concept of parent
classes. Instead, super() is all about the MRO which is computed
dynamically (unknowable at the time a class is written). Every class
in the MRO implementing the target method *must* call super() to give
the next class in the MRO a chance to run.

IOW, using super() means "I'm in the MRO and I got a chance to run;
now the next class in the MRO gets its chance." Since the MRO is
only knowable at runtime, the sole job of super() is to figure out
which is "the next class in the MRO".
From: Michele Simionato on
Everything you ever wanted to know about super is collected here:
http://micheles.googlecode.com/hg/artima/python/super.pdf

M.S.