super(cls, instance)
和super(cls, subclass)
不会都返回cls
的超类吗?
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, eg 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 (ie 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 .
super(cls, instance).attr
inspects the MRO of the class of instance
(ie instance.__class__.__mro__
), looks up the next class after cls
in the MRO 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 MRO of subclass
(ie subclass.__mro__
), looks up the next class after cls
in the MRO 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'
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.