这可以按预期工作:
>>> class Foo(object):
... @classmethod
... def hello(cls):
... print 'hello, foo'
...
>>> class Bar(Foo):
... @classmethod
... def hello(cls):
... print 'hello, bar'
... super(Bar, cls).hello()
...
>>> b = Bar()
>>> b.hello()
hello, bar
hello, foo
我也可以明确地调用基类:
>>> class Bar(Foo):
... @classmethod
... def hello(cls):
... print 'hello, bar'
... Foo.hello()
...
>>> b = Bar()
>>> b.hello()
hello, bar
hello, foo
我想知道为什么我不能省略super
的第一个参数,如下所示:
>>> class Bar(Foo):
... @classmethod
... def hello(cls):
... print 'hello, bar'
... super(Bar).hello()
...
>>> b = Bar()
>>> b.hello()
hello, bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in hello
AttributeError: 'super' object has no attribute 'hello'
当没有第二个参数的super
调用的结果似乎是超类型中的类类型时:
>>> class Bar(Foo):
... @classmethod
... def hello(cls):
... print Foo, type(Foo)
... print super(Bar), type(super(Bar))
... print cls, type(cls)
...
>>> b = Bar()
>>> b.hello()
<class '__main__.Foo'> <type 'type'>
<super: <class 'Bar'>, NULL> <type 'super'>
<class '__main__.Bar'> <type 'type'>
我想我只是想知道这里的设计。为什么我需要将类对象传递给超级调用以获取对基类类型Foo
的引用?对于普通方法,将self
传递给函数是有意义的,因为它需要将基类类型绑定到类的实际实例。但是类方法不需要类的特定实例。
修改:
我在Python 3.2中得到了与上面2.7 super(Bar).hello()
中相同的错误。但是,我可以简单地执行super().hello()
,并且工作正常。
答案 0 :(得分:10)
super()
返回descriptor,需要两个项目:
对于两个参数(和隐式零参数 * )的情况,第二个参数用于绑定,但如果你没有传入第二个参数,super()
就无法调用描述符协议,用于绑定返回的函数,类方法,属性或其他描述符。 classmethods
仍然是描述符并受约束;绑定到类而不是实例,但super()
不知道描述符将如何使用您绑定的上下文。
super()
不应该也不知道你正在查找类方法而不是常规方法;类方法仅与常规方法不同,因为它们的.__get__()
方法的行为不同。
为什么要绑定类方法?因为当您继承Foo
但不覆盖.hello()
时,调用Bar.hello()
会调用Foo.__dict__['hello']
函数,将其绑定到Bar
并且你hello(cls)
的第一个参数将是该子类,而不是Foo
。
如果没有第二个参数,super()
将返回一个可以在以后手动绑定的未绑定对象。您可以使用.__get__()
实例提供的super()
方法自行绑定:
class Bar(Foo):
@classmethod
def hello(cls):
print 'hello, bar'
super(Bar).__get__(cls, None).hello()
没有上下文的实例上的 super().__get__()
会有效地返回带有上下文集的新super()
实例。在具有上下文.__get__()
的实例上,只返回self
;它已经受到约束。
* 在Python 3中,在绑定方法内调用不带参数的super()
将使用调用框隐式发现类型和绑定对象是什么,所以你不再在这种情况下必须显式传入类型和对象参数。 Python 3实际上为此目的向方法添加了一个隐式__class__
闭包变量。请参阅PEP 3135和Why is Python 3.x's super() magic?