trouble understanding super()

J

John Salerno

Here's some code from Python in a Nutshell. The comments are lines from
a previous example that the calls to super replace in the new example:

class A(object):
def met(self):
print 'A.met'

class B(A):
def met(self):
print 'B.met'
# A.met(self)
super(B, self).met()

class C(A):
def met(self):
print 'C.met'
# A.met(self)
super(C, self).met()

class D(B, C):
def met(self):
print 'D.met'
# B.met()
# C.met()
super(D, self).met()

Then you call D().met()

Now, I understand that the commented code would cause A.met to be called
twice. But why does the second version (with super) not also do this? I
guess my problem lies in not understanding exactly what the super
function returns.

super(D, self).met() seems like it would return something that has to do
with both B and C, which each in turn return a superobject having to do
with A, so why isn't A.met called twice still?

Thanks!
 
S

Simon Forman

John said:
Here's some code from Python in a Nutshell. The comments are lines from
a previous example that the calls to super replace in the new example:

class A(object):
def met(self):
print 'A.met'

class B(A):
def met(self):
print 'B.met'
# A.met(self)
super(B, self).met()

class C(A):
def met(self):
print 'C.met'
# A.met(self)
super(C, self).met()

class D(B, C):
def met(self):
print 'D.met'
# B.met()
# C.met()
super(D, self).met()

Then you call D().met()

Now, I understand that the commented code would cause A.met to be called
twice. But why does the second version (with super) not also do this? I
guess my problem lies in not understanding exactly what the super
function returns.

super(D, self).met() seems like it would return something that has to do
with both B and C, which each in turn return a superobject having to do
with A, so why isn't A.met called twice still?

Thanks!


Basically super(class_, self).method looks in self's mro (it's list of
base classes) for class class_, and then starts searching *after* class
class_ for the next class that implements the method.

In this case the object's (instance of D) mro will be (D, B, C, A,
object), so as super gets called in each class, it looks in that list
(tuple, whatever) for the class following it (actually the next class
following it that implements the method).

Since no class appears in that list more than once, each class's
implementation of the method will only be called once.


HTH,
~Simon


Also, if you haven't already, read:
http://www.python.org/download/releases/2.2.3/descrintro/#cooperation
 
J

John Salerno

Simon said:
In this case the object's (instance of D) mro will be (D, B, C, A,
object), so as super gets called in each class, it looks in that list
(tuple, whatever) for the class following it (actually the next class
following it that implements the method).

Since no class appears in that list more than once, each class's
implementation of the method will only be called once.

But after super(D, self).met() is called, doesn't that then call both
super(B, self).met() and super(C, self).met()? If so, how does that
avoid calling A.met twice? Or is that not what's happening?

Here's what I think gets called, in order, after running D().met():

print 'D.met'
super(D, self).met()
print 'B.met'
super(B, self).met()
print 'A.met'
print 'C.met'
super(C, self).met()
print 'A.met'
 
D

Duncan Booth

John said:
But after super(D, self).met() is called, doesn't that then call both
super(B, self).met() and super(C, self).met()? If so, how does that
avoid calling A.met twice? Or is that not what's happening?

If you have an instance of a B then super(B,self).met() will call A.met(),
but if self is actually an instance of a D, then super(B,self).met()
actually calls C.met().

That is why super needs both the class and the instance: so it can jump
sideways across the inheritance diamond instead of always passing calls to
the base of the current class.
 
J

John Salerno

Duncan said:
If you have an instance of a B then super(B,self).met() will call A.met(),
but if self is actually an instance of a D, then super(B,self).met()
actually calls C.met().

That is why super needs both the class and the instance: so it can jump
sideways across the inheritance diamond instead of always passing calls to
the base of the current class.

Oh, I think I get it! So what's happening is this:

1. the MRO in this case is always (D, B, C, A, object)
2. super(D, self).met() looks in B
3. super(B, self).met() looks in C
4. super(C, self).met() looks in A

Right? So it's like making a ladder? I guess my confusion came when I
thought that a call to super(B, self).met() also called A.met, but I
guess it stops at C and lets C call it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,735
Latest member
HikmatRamazanov

Latest Threads

Top