Using super with a class method
Solution 1
Sometimes texts have to be read more for the flavor of the idea rather than for the details. This is one of those cases.
In the linked page, Examples 2.5, 2.6 and 2.7 should all use one method, do_your_stuff
. (That is, do_something
should be changed to do_your_stuff
.)
In addition, as Ned Deily pointed out, A.do_your_stuff
has to be a class method.
class A(object):
@classmethod
def do_your_stuff(cls):
print 'This is A'
class B(A):
@classmethod
def do_your_stuff(cls):
super(B, cls).do_your_stuff()
B.do_your_stuff()
super(B, cls).do_your_stuff
returns a bound method (see footnote 2). Since cls
was passed as the second argument to super()
, it is cls
that gets bound to the returned method. In other words, cls
gets passed as the first argument to the method do_your_stuff()
of class A.
To reiterate: super(B, cls).do_your_stuff()
causes A
's do_your_stuff
method to be
called with cls
passed as the first argument. In order for that to work, A
's
do_your_stuff
has to be a class method. The linked page doesn't mention that,
but that is definitively the case.
PS. do_something = classmethod(do_something)
is the old way of making a classmethod.
The new(er) way is to use the @classmethod decorator.
Note that super(B, cls)
can not be replaced by super(cls, cls)
. Doing so could lead to infinite loops. For example,
class A(object):
@classmethod
def do_your_stuff(cls):
print('This is A')
class B(A):
@classmethod
def do_your_stuff(cls):
print('This is B')
# super(B, cls).do_your_stuff() # CORRECT
super(cls, cls).do_your_stuff() # WRONG
class C(B):
@classmethod
def do_your_stuff(cls):
print('This is C')
# super(C, cls).do_your_stuff() # CORRECT
super(cls, cls).do_your_stuff() # WRONG
C.do_your_stuff()
will raise RuntimeError: maximum recursion depth exceeded while calling a Python object
.
If cls
is C
, then super(cls, cls)
searches C.mro()
for the class that comes after C
.
In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]
Since that class is B
, when cls
is C
, super(cls, cls).do_your_stuff()
always calls B.do_your_stuff
. Since super(cls, cls).do_your_stuff()
is called inside B.do_your_stuff
, you end up calling B.do_your_stuff
in an infinite loop.
In Python3, the 0-argument form of super
was added so super(B, cls)
could be replaced by super()
, and Python3 will figure out from context that super()
in the definition of class B
should be equivalent to super(B, cls)
.
But in no circumstance is super(cls, cls)
(or for similar reasons, super(type(self), self)
) ever correct.
Solution 2
In Python 3, you can skip specifying arguments for super
,
class A:
@classmethod
def f(cls):
return "A's f was called."
class B(A):
@classmethod
def f(cls):
return super().f()
assert B.f() == "A's f was called."
Solution 3
I've updated the article to make it a bit clearer: Python Attributes and Methods # Super
Your example using classmethod above shows what a class method is - it passes the class itself instead of the instance as the first parameter. But you don't even need an instance to call the method, for e.g.:
>>> class A(object):
... @classmethod
... def foo(cls):
... print cls
...
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>
Solution 4
The example from the web page seems to work as published. Did you create a do_something
method for the superclass as well but not make it into a classmethod? Something like this will give you that error:
>>> class A(object):
... def do_something(cls):
... print cls
... # do_something = classmethod(do_something)
...
>>> class B(A):
... def do_something(cls):
... super(B, cls).do_something()
... do_something = classmethod(do_something)
...
>>> B().do_something()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in do_something
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)
dza
linux freebsd archlinux debian ubuntu docker firefox gnupg shell posix zsh bash awk curl grep vim openssh openwrt reversing cracking gdb debugging asm When Things are Dim Give 'Em Vim denmark opensource I prefer my websites without javascript; static, with asciiart
Updated on July 08, 2022Comments
-
dza almost 2 years
I'm trying to learn the super() function in Python.
I thought I had a grasp of it until I came over this example (2.6) and found myself stuck.
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "test.py", line 9, in do_something do_something = classmethod(do_something) TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead) >>>
It wasn't what I expected when I read this line right before the example:
If we're using a class method, we don't have an instance to call super with. Fortunately for us, super works even with a type as the second argument. --- The type can be passed directly to super as shown below.
Which is exactly what Python tells me is not possible by saying that do_something() should be called with an instance of B.
-
dza over 14 yearsNo, my A class looks like this: class A(object): def do_your_stuff(self): print "this is A" Is it necessary to have "class A" as you posted it? (with do_something = classmethod(do_something)) ? I feel like the document didn't tell anything about this ..
-
Ned Deily over 14 yearsThe whole point of the
super
call in the B do_something method is to call a method of that name in one of its superclasses. If there isn't one in A (or in Object), the B().do_something() call fails withsuper object has no attribute do_something
. ~unutbu rightly points out that the example in the document is faulty. -
unutbu over 14 yearsFor an explanation of classmethods, perhaps you'll find this helpful: stackoverflow.com/questions/1669445/…
-
Tankobot over 6 yearsThis answer could be moved to another question if this particular question is dealing with Python 2 specifically (it's hard to tell since the linked website, CafePy, is no longer available).
-
George Moutsopoulos over 5 yearsAre there pitfalls in using super(cls, cls)?
-
unutbu over 5 years@GeorgeMoutsopoulos:
super(cls, cls)
is almost certainly a mistake. I've edited the post above to explain why. -
madtyn over 5 yearsIt's not working for me in a project of mine. It is giving
RuntimeError: super(): no arguments