Won’t super(cls, instance)
and super(cls, subclass)
both return the superclass of cls
?
2 Answers
The difference is huge; super()
with a type (class) second argument instead of an object (instance) gives you unbound methods, not bound methods (just like accessing those methods on a class would).
I'll explain first how super()
works with an instance second argument.
super()
inspects the MRO of self
, finds the first argument (type
or supertype
) in the MRO, then finds the next object that has the requested attribute.
Demo:
>>> class BaseClass(object):
... def foo(self): return 'BaseClass foo'
...
>>> class Intermediary(BaseClass):
... def foo(self): return 'Intermediary foo'
...
>>> class Derived(Intermediary):
... def foo(self): return 'Derived foo'
...
>>> d = Derived()
>>> d.foo()
'Derived foo'
>>> super(Derived, d).foo
<bound method Intermediary.foo of <__main__.Derived object at 0x10ef4de90>>
>>> super(Derived, d).foo()
'Intermediary foo'
>>> super(Intermediary, d).foo()
'BaseClass foo'
>>> Derived.__mro__
(<class '__main__.Derived'>, <class '__main__.Intermediary'>, <class '__main__.BaseClass'>, <type 'object'>)
The MRO of Derived
is (Derived, Intermediary, BaseClass)
; super()
finds this MRO by looking at the second argument, using type(d).__mro__
. The search for foo
starts at the next class after the first argument given.
The foo()
method is bound here, you can just call it.
If you give super()
a type as the second argument, then it'll use the MRO of that type, e.g. instead of using type(instance).__mro__
it just goes for type.__mro__
. However it then has no instance to bind the methods to. super(supertype, type).foo
is just the (unbound) function object:
>>> super(Intermediary, Derived).foo
<function BaseClass.foo at 0x106dd6040>
>>> super(Intermediary, Derived).foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required positional argument: 'self'
>>> super(Intermediary, Derived).foo(d)
'BaseClass foo'
To call .foo()
I have to explicitly pass in a self
argument.
(In Python 2, the above would return a foo
unbound method object instead of a function, but the principle is the same).
The method returned is also, again, from the next class in the MRO chain; BaseClass.foo
was returned there.
This is down to the function.__get__
method (i.e. the descriptor protocol, responsible for binding), as it returns itself (or, in Python 2, an unbound method) when passed a class to bind to. (For classmethod
objects, __get__
does return a bound object when passed in a class).
So, TL;DR, for methods super(type, object)
returns a bound method, super(supertype, type)
returns unbound methods. The goal was to make it possible to store this object as a class-private attribute to avoid having to keep looking up the class object, see How to use super() with one argument?. It's use-case has been obsoleted entirely in Python 3 so it is slated for deprecation.

- 1,048,767
- 296
- 4,058
- 3,343
-
I believe you but I did not find any information about this on official documents. Is there any official explain about this? – Kramer Li Jul 17 '17 at 09:12
-
@KramerLi: It's all covered in the [`super()` documentation](https://docs.python.org/3/library/functions.html#super). – Martijn Pieters Jul 17 '17 at 09:19
-
@KramerLi: I recently 'ported' the implementation to Python to answer another question: [What is the type of the super object returned by super()?](//stackoverflow.com/a/44994572). Would that help in understanding? – Martijn Pieters Jul 17 '17 at 09:49
-
Thanks, your answer here already very clear. The most important info to me from your answer is that "super() with a type (class) second argument instead of an object (instance) gives you unbound methods". I think that this is a very important info that the python official documents should mention. But I really did not find this kind of information on the official documents(I also read the link you provided). So I am just wondering did I missed anything from the official doc ? – Kramer Li Jul 17 '17 at 11:25
-
@KramerLi: I perhaps put more emphasis on that than needed, but I do see the documentation is not as clear on that the same binding rules apply as normal instance and class attribute access. – Martijn Pieters Jul 17 '17 at 11:28
-
@Maggyero: sorry, but I had to roll back those edits. You changed huge swathes of my answer, and I spent a lot of headscratching trying to find a reference I knew was around somewhere but was removed by your edit. I don’t really have time to review right now if there is anything I want to salvage. Please don’t edit my posts to this extent. – Martijn Pieters May 07 '21 at 22:41
-
Yes my multiple edits ended up in a big change, so I should have posted a separate answer. That is what I did eventually. – Géry Ogam May 08 '21 at 00:02
super(cls, instance).attr
inspects the M.R.O. of the class of instance
(i.e. instance.__class__.__mro__
), looks up the next class after cls
in the M.R.O. that has an attribute attr
, and returns the result of attr.__get__(instance, instance.__class__)
if it has a __get__
method or returns attr
if it has no __get__
method. This case is used in functions:
>>> class A:
... def f(self): return 'A.f'
...
>>> class B(A):
... def f(self): return 'B.f ' + super(B, self).f()
...
>>> B().f()
'B.f A.f'
super(cls, subclass).attr
inspects the M.R.O. of subclass
(i.e. subclass.__mro__
), looks up the next class after cls
in the M.R.O. that has an attribute attr
, and returns the result of attr.__get__(None, subclass)
if it has a __get__
method or returns attr
if it has no __get__
method. This case is used in classmethod
:
>>> class A:
... @classmethod
... def f(cls): return 'A.f'
...
>>> class B(A):
... @classmethod
... def f(cls): return 'B.f ' + super(B, cls).f()
...
>>> B.f()
'B.f A.f'
For function attributes, super(cls, instance).attr
returns a bound method of instance
, while super(cls, subclass).attr
returns a function:
>>> class A:
... def f(self): return 'A.f'
...
>>> class B(A):
... def f(self): return 'B.f'
...
>>> b = B()
>>> b.f
<bound method B.f of <__main__.B object at 0x10e7d3fa0>>
>>> B.f
<function B.f at 0x10e7ea790>
>>> b.f()
'B.f'
>>> B.f(b)
'B.f'
>>> super(B, b).f
<bound method A.f of <__main__.B object at 0x10e7d3fa0>>
>>> super(B, B).f
<function A.f at 0x10e7ea700>
>>> super(B, b).f()
'A.f'
>>> super(B, B).f(b)
'A.f'
For classmethod
attributes, super(cls, instance).attr
and super(cls, subclass).attr
return a bound method of respectively instance.__class__
and subclass
:
>>> class A:
... @classmethod
... def f(cls): return 'A.f'
...
>>> class B(A):
... @classmethod
... def f(cls): return 'B.f'
...
>>> b = B()
>>> b.f
<bound method B.f of <class '__main__.B'>>
>>> B.f
<bound method B.f of <class '__main__.B'>>
>>> b.f()
'B.f'
>>> B.f()
'B.f'
>>> super(B, b).f
<bound method A.f of <class '__main__.B'>>
>>> super(B, B).f
<bound method A.f of <class '__main__.B'>>
>>> super(B, b).f()
'A.f'
>>> super(B, B).f()
'A.f'

- 6,336
- 4
- 38
- 67