Jumping over in the class hierarchy

P

Pupeno

Hello,
I want to jump over a method in the class hierarchy, that is: If I have
class A(object), clas B(A), class C(B) and in C, I want a method to do
exactly what A does but not what B does in its reimplementation, would it
be correct to do: super(A, super(B, self)).method() in C ?
Thank you.
 
L

Laszlo Nagy

Pupeno írta:
Hello,
I want to jump over a method in the class hierarchy, that is: If I have
class A(object), clas B(A), class C(B) and in C, I want a method to do
exactly what A does but not what B does in its reimplementation, would it
be correct to do: super(A, super(B, self)).method() in C ?
Thank you.
A.method(self)

Cheers,

Laszlo
 
S

sjdevnull

Pupeno said:
Hello,
I want to jump over a method in the class hierarchy, that is: If I have
class A(object), clas B(A), class C(B) and in C, I want a method to do
exactly what A does but not what B does in its reimplementation, would it
be correct to do: super(A, super(B, self)).method() in C ?
Thank you.

There's no reason to mess with super. Explicitly call A.method()
 
J

Jan Niklas Fingerle

Pupeno said:
be correct to do: super(A, super(B, self)).method() in C ?

Why do you want to use super? Is there any diamond shaped inheritance
in sight? Anyway, have you actually tried, what you suggested? Well, ...

----------------------8<------------------------------------
class A(object):
def my_method(self):
print 'in A'

class B(A):
def my_method(self):
print 'in B'
super(B, self).my_method()

class C(B):
def my_method(self):
print 'in C'
super(A, super(B, self)).my_method()

print "A..."
A().my_method()
print "B..."
B().my_method()
print "C..."
C().my_method()
---------------------->8------------------------------------

leads to

----------------------8<------------------------------------
A...
in A
B...
in B
in A
C...
in C
Traceback (most recent call last):
File "test.py", line 20, in ?
C().my_method()
File "test.py", line 13, in my_method
super(A, super(B, self)).my_method()
TypeError: super(type, obj): obj must be an instance or subtype of type
---------------------->8------------------------------------

, at least on my machine ;-)

"obj must be an instance or subtype of type". So, what's the type
of "super(B, self)"? Let's see...

----------------------8<------------------------------------
class A(object):
def my_method(self):
print 'in A'

class B(A):
def my_method(self):
print 'in B'
super(B, self).my_method()

class C(B):
def my_method(self):
print 'in C'
print type(super(B, self))

C().my_method()
---------------------->8------------------------------------

----------------------8<------------------------------------
in C
<type 'super'>
---------------------->8------------------------------------

Seems, that super is a class. In fact "help(super)" at the
interactive prompt tells you that "super(type, obj) -> bound super
object; requires isinstance(obj, type)". Now, the interactive help
isn't much more help, if you don't know what super does. This isn't
the interactive help's (aka super's doc string's) fault. It's just
that the docstring would become veeeery long if it wanted to
introduce the concepts behind super.

Well, now, what does super do? Let's take a simple example. Well,
at least the simplest example super was really meant to handle:
(real) diamond shape inheritance.

----------------------8<------------------------------------
class A(object):
def my_method(self):
print 'in A'

class B(A):
def my_method(self):
print 'in B'
super(B, self).my_method()

class C(A):
def my_method(self):
print 'in C'
super(C, self).my_method()

class D(B,C):
def my_method(self):
print 'in D'
super(D, self).my_method()

obj = D()
obj.my_method()
---------------------->8------------------------------------

----------------------8<------------------------------------
in D
in B
in C
in A
---------------------->8------------------------------------

What happens here?

(1) We instantiate a D object named "obj" and call its my_method.

(2) We instantiate a super object. We tell it, that we are
"in" 'obj' and that we are interested in the next base class
after handling "D". Super "asks" obj for it's ancestry (which
is D-B-C-A). The next ancestor in this list is B. Therefore
super(D, self).my_method() delegates the call to B.my_method.

(3) We're in B.my_method now.

We instantiate a super object. We tell it, that we are
"in" 'obj' and that we are interested in the next base class
after handling "B". Super "asks" obj for it's ancestry (which
is D-B-C-A). The next ancestor in this list is C. Therefore
super(B, self).my_method() delegates the call to C.my_method.

(4) We're in C.my_method now.

We instantiate a super object. We tell it, that we are
"in" 'obj' and that we are interested in the next base class
after handling "C". Super "asks" obj for it's ancestry (which
is D-B-C-A). The next ancestor in this list is A. Therefore
super(B, self).my_method() delegates the call to A.my_method.

(5) We're in A.my_method now. Nothing more of interest will happen...

Note:

(a) C.my_method "gets called by" B.my_method, even though these
two classes don't "know" anything about each other.
(b) C.my_method would never have been called, if D used super,
but B didn't (but called its parent directly).
(c) Even though B and C don't know anything about each other,
they have to care for each other's argument lists. Well, yes,
this seems to be no problem, since a child classes method
should have "the same" argument list as the base class anyway.
Yet, this doesn't hold for __init__, so you have to handle
__init__ with special care (i.e. you should only use **kwargs and
propagate *all* parameters).
(d) "super()" *does not* "cast" a child class object to the
parent class (or something like this). "super(B, self)"
*does not* return self as "B's super class" object. This
wouldn't work correctly for diamond shapes anyway.

Now that we've understood, what super() does, you could use

----------------------8<------------------------------------
class A(object):
def my_method(self):
print 'in A'

class B(A):
def my_method(self):
print 'in B'
super(B, self).my_method()

class C(B):
def my_method(self):
print 'in C'
super(B, self).my_method()

print "A..."
A().my_method()
print "B..."
B().my_method()
print "C..."
C().my_method()
---------------------->8------------------------------------

----------------------8<------------------------------------
A...
in A
B...
in B
in A
C...
in C
in A
---------------------->8------------------------------------

, but: Is it really the super magic, that you need? As long, as
you don't have diamond shape inheritance, you can always call the
base classes method directly. And casually using super doesn't help,
either, because (see note (b)) all classes in the diamond shape *must*
use super for the magic to work. In my world, this is only worth it,
whenever I really need this magic.

So, to cut a long story short, I would just use:

----------------------8<------------------------------------
class A(object):
def my_method(self):
print 'in A'

class B(A):
def my_method(self):
print 'in B'
A.my_method(self)

class C(A):
def my_method(self):
print 'in C'
A.my_method(self)

print "A..."
A().my_method()
print "B..."
B().my_method()
print "C..."
C().my_method()
---------------------->8------------------------------------

----------------------8<------------------------------------
A...
in A
B...
in B
in A
C...
in C
in A
---------------------->8------------------------------------

I hope, this helped. FWIW, i think super is a cool tool. Like a chain
saw. Use it where appropriate, then it will be real help. I also don't
consider super() "harmful" (Google will tell you, what I'm referring
to.) I just consider it to be named misleadingly, since it does *not*
return the super class or an object re-typed to the super class. But,
then again, Python is not Java... ;-)

Cheers,
--Jan Niklas
 
R

Raymond Hettinger

Pupeno said:
I want to jump over a method in the class hierarchy, that is: If I have
class A(object), clas B(A), class C(B) and in C, I want a method to do
exactly what A does but not what B does in its reimplementation, would it
be correct to do: super(A, super(B, self)).method() in C ?

You can use __bases__ to climb the class hierarchy:

def f(self):
print 1 def f(self):
print 2 def f(self):
print 3
def g(self):
C.__bases__[0].__bases__[0].f(self) # go up two levels1



Raymond
 

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

Staff online

Members online

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top