I wrote a simple test to investigate what CPython does for super
:
class A:
pass
class B(A):
def f(self):
return super()
@classmethod
def g(cls):
return super()
def h(selfish):
selfish = B()
return super()
class C(B):
pass
c = C()
for method in 'fgh':
super_object = getattr(c, method)()
print(super_object, super_object.__self__, super_object.__self_class__, super_object.__thisclass__) # (These methods were found using dir.)
The zero-argument super
call returns an object that stores three things:
__self__
stores the object whose name matches the first parameter of the method—even if that name has been reassigned.
__self_class__
stores its type, or itself in the case of a class method.
__thisclass__
stores the class in which the method is defined.
(It is unfortunate that __thisclass__
was implemented this way rather than fetching an attribute on the method because it makes it impossible to use the zero-argument form of super
with meta-programming.)
The object returned by super
implements getattribute
, which forwards method calls to the type found in the __mro__
of __self_class__
one step after __thisclass__
.