Reputation: 529
sup = super(B, self)
and sup2 = super(B, B)
have indistinguishable representations, they both look like this:
<super: <class 'B'>, <B object>>
while super(B, self).spam
gives a bound method, super(B, B)
only works with class methods, so super(B, B).cls_spam()
, like demonstrated below. You can't use it for regular methods, you get a normal function:
class A:
@classmethod
def cls_spam(cls):
print('A.cls_spam: cls =', cls)
def spam(self):
print('A.spam: self =', self)
class B(A):
def call_spam(self):
sup = super(B, self)
print('B.call_spam: sup =', sup)
print('B.call_spam: sup.spam =', sup.spam)
print('B.call_spam: sup.cls_spam =', sup.cls_spam)
sup.spam()
sup.cls_spam()
sup2 = super(B, B)
print('B.call_spam: sup2 =', sup2)
print('B.call_spam: sup2.css_spam =', sup2.cls_spam)
# can't call sup2.spam(), not without giving it self explicitly
sup2.cls_spam()
The following interactive session illustrates:
>>> b = B()
>>> b.call_spam3()
B.call_spam: sup = <super: <class 'B'>, <B object>>
B.call_spam: sup.spam = <bound method A.spam of <__main__.B object at 0x108830b50>>
B.call_spam: sup.cls_spam = <bound method A.cls_spam of <class '__main__.B'>>
A.spam: self = <__main__.B object at 0x108830b50>
A.cls_spam: cls = <class '__main__.B'>
B.call_spam: sup2 = <super: <class 'B'>, <B object>>
B.call_spam: sup2.css_spam = <bound method A.cls_spam of <class '__main__.B'>>
A.cls_spam: cls = <class '__main__.B'>
super()
is a complicated subject, if the demonstrated above behavior is documented understanding it would help me a lot.
Using Python 3.5.3,Debian GNU/Linux 9.11 (stretch)
Upvotes: 0
Views: 98
Reputation: 1123710
super()
is meant to be useful both in class methods and in regular methods. In a classmethod
there is no instance, you only have access to the class, so the second argument to super()
accepts either an instance or a class. That at least is covered in the documentation for super()
:
If the second argument is an object,
isinstance(obj, type)
must be true. If the second argument is a type,issubclass(type2, type)
must be true (this is useful for classmethods).
Bold emphasis mine.
Now, the primary task super()
has to perform is to search for attributes along the Method Resolution Order (MRO) list of classes, given a starting point. The starting point is the first argument, but the MRO has to be taken from the second argument; if you use super()
in class Foo
, you can't know at that time if Foo
might have been subclassed, which can alter the MRO of the second argument. So, for this purpose, super()
tracks two pieces of information:
There is also a 3rd piece of information, the instance or class to which attributes are bound, when you do an attribute lookup. That's simply the second argument itself, so either an instance or class. The repr()
output reflects just the first two values, in large part because those are 'hidden' in that super()
, without arguments, gets its arguments from the context and so you can't, as easily see what the starting point is, or what the MRO source is, but you can much more easily see the first argument to the method (so self
or cls
).
If you want to distinguish between your two super()
instances, you can instead look at the __self__
attribute, which represents that 3rd piece of information:
>>> sup = super(B, b)
>>> sup.__self__
<__main__.B object at 0x108b4c520>
>>> sup2 = super(B, B)
>>> sup2.__self__
<class '__main__.B'>
The other two pieces of information you do see in the repr()
output are the __thisclass__
and __self_class__
attributes, respectively:
>>> sup.__thisclass__, sup.__self_class__
(<class '__main__.B'>, <class '__main__.B'>)
This is easier to spot when you use a different class as the first argument:
>>> sup_a = super(A, b)
>>> sup_a
<super: <class 'A'>, <B object>>
>>> sup_a.__thisclass__, sup_a.__self_class__
(<class '__main__.A'>, <class '__main__.B'>)
Upvotes: 4