Calling a base class's classmethod in Python
Solution 1
If you're using a new-style class (i.e. derives from object
in Python 2, or always in Python 3), you can do it with super()
like this:
super(Derived, cls).do(a)
This is how you would invoke the code in the base class's version of the method (i.e. print cls, a
), from the derived class, with cls
being set to the derived class.
Solution 2
this has been a while, but I think I may have found an answer. When you decorate a method to become a classmethod the original unbound method is stored in a property named 'im_func':
class Base(object):
@classmethod
def do(cls, a):
print cls, a
class Derived(Base):
@classmethod
def do(cls, a):
print 'In derived!'
# Base.do(cls, a) -- can't pass `cls`
Base.do.im_func(cls, a)
if __name__ == '__main__':
d = Derived()
d.do('hello')
Solution 3
Building on the answer from @David Z using:
super(Derived, cls).do(a)
Which can be further simplified to:
super(cls, cls).do(a)
I often use classmethods to provide alternative ways to construct my objects. In the example below I use the super functions as above for the class method load that alters the way that the objects are created:
class Base():
def __init__(self,a):
self.a = a
@classmethod
def load(cls,a):
return cls(a=a)
class SubBase(Base):
@classmethod
def load(cls,b):
a = b-1
return super(cls,cls).load(a=a)
base = Base.load(a=1)
print(base)
print(base.a)
sub = SubBase.load(b=3)
print(sub)
print(sub.a)
Output:
<__main__.Base object at 0x128E48B0>
1
<__main__.SubBase object at 0x128E4710>
2
Sridhar Ratnakumar
Updated on October 13, 2020Comments
-
Sridhar Ratnakumar over 3 years
Consider the following code:
class Base(object): @classmethod def do(cls, a): print cls, a class Derived(Base): @classmethod def do(cls, a): print 'In derived!' # Base.do(cls, a) -- can't pass `cls` Base.do(a) if __name__ == '__main__': d = Derived() d.do('hello') > $ python play.py > In derived! > <class '__main__.Base'> msg
From
Derived.do
, how do I callBase.do
?I would normally use
super
or even the base class name directly if this is a normal object method, but apparently I can't find a way to call the classmethod in the base class.In the above example,
Base.do(a)
printsBase
class instead ofDerived
class. -
Sridhar Ratnakumar almost 15 yearsuh uh .. how come it never occured to me that I can use
super
on classmethods too. -
Sridhar Ratnakumar almost 15 yearsThe
cls
argument will then be bound toBase
instead ofDerived
-
Alex Q almost 13 yearsNote: This approach works for old style classes where super() doesn't work
-
user192127 about 12 yearswhat works for me is this - which looks (a lot) like Ned's answer: where self derives from QGraphicsView which has paintEvent(QPaintEvent) def paintEvent (self, qpntEvent): print dir(self) QGraphicsView.paintEvent(self, qpntEvent)
-
dtheodor about 10 yearsAlso available as
__func__
in python 2.7 and 3 -
ars-longa-vita-brevis almost 10 yearsthis only works (due to a limitation imposed by super) if the base derives from object, right? what do you do if that's not the case?
-
David Z almost 10 yearsYeah, this only works for new-style classes, which derive from
object
. (at least in Python 2, but in Py3 I think all classes are new-style, IIRC) Otherwise you have to doBase.do(self, ...)
, I think, thereby hard-coding the name of the superclass. -
Ray over 6 yearsInside
Derived.do()
, isn'tcls
the same asDerived
? -
David Z over 6 years@Ray If it is actually an instance of
Derived
but not of a subclass, then yes. -
Martin Grůber over 3 yearsReplacing
super(Derived, cls).do(a)
withsuper(cls, cls).do(a)
is not a good way. It will not work (it actually will cause an exception) when you have anotherclass SubSubBase(SubBase)
withoutload()
method defined and you will try to use it. -
MestreLion over 2 years@MartinGrůber: so what is the correct way in Python3? Simply
super().load(...)
will work correctly for classmethods? -
Martin Grůber over 2 years@MestreLion Not sure what is the correct way but I would stay with
super(Derived, cls).do(a)
which works AFAIK.