为什么类方法的super需要第二个参数? [英] Why does a classmethod's super need a second argument?

查看:287
本文介绍了为什么类方法的super需要第二个参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可以按预期工作:

>>> 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

我还可以显式调用基类:

I can also call the base class explicitly:

>>> class Bar(Foo):
...   @classmethod
...   def hello(cls):
...     print 'hello, bar'
...     Foo.hello()
... 
>>> b = Bar()
>>> b.hello()
hello, bar
hello, foo

我想知道为什么我不能这样省略super的第一个参数:

I was wondering why I can't omit the first argument to super, like this:

>>> 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调用的结果似乎是超类型内部的类类型时:

when the result of the super call without a second argument seems to be a class type inside a super type:

>>> 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传递给函数是有意义的,因为它需要将基类类型绑定到该类的实际实例.但是类方法不需要该类的特定实例.

I guess I'm just wondering about the design here. Why would I need to pass the class object into the super call to get a reference to the base class type Foo? For a normal method, it makes sense to pass self to the function, since it needs to bind the base class type to an actual instance of the class. But a classmethod doesn't need a specific instance of the class.

编辑: 我在Python 3.2中遇到的错误与在2.7中对于super(Bar).hello()的错误相同.但是,我可以简单地执行super().hello(),并且效果很好.

EDIT: I get the same error in Python 3.2 as I do above in 2.7 for super(Bar).hello(). However, I can simply do super().hello() and that works fine.

推荐答案

super()返回描述符,并且需要两项:

super() returns a descriptor, and needs two items:

  • 搜索类层次结构的起点.
  • bind 的参数返回的方法.
  • A starting point from which to search the class hierarchy.
  • The argument to bind the returned methods.

对于两个参数(以及隐式零参数 * ),第二个参数用于绑定,但是如果您不传入第二个参数,则super()无法调用描述符绑定返回的函数,类方法,属性或其他描述符的协议. classmethods仍然是描述符并已绑定;绑定到类而不是实例,但是super() 不知道描述符将如何使用绑定的上下文.

For the two argument (and implicit zero-argument *) case the second argument is used to bind to, but if you do not pass in a second argument, super() cannot invoke the descriptor protocol to bind the returned functions, classmethods, properties or other descriptors. classmethods are still descriptors and are bound; the bind to a class and not an instance, but super() does not know how the descriptor will use the context to which you bind.

super()不应,也不能知道您正在查找的是类方法而不是常规方法.类方法与常规方法的不同之处仅在于它们的.__get__()方法的行为不同.

super() should not and cannot know that you are looking up a class method instead of a regular method; class methods only differ from regular methods because their .__get__() method acts differently.

为什么要绑定类方法?因为当您继承Foo的子类但覆盖.hello()时,调用Bar.hello()会调用Foo.__dict__['hello']函数,将其绑定到Bar,而您对hello(cls)的第一个参数将是子类,而不是Foo.

Why are class methods bound? Because when you subclass Foo but do not override .hello(), calling Bar.hello() invokes the Foo.__dict__['hello'] function, binds it to Bar and your first argument to hello(cls) will be that subclass, not Foo.

没有第二个参数,super()返回一个未绑定的对象,以后可以手动对其进行绑定.您可以使用super()实例提供的.__get__()方法自己进行绑定:

Without a second argument, super() returns an unbound object that can manually be bound later on. You can do the binding yourself using the .__get__() method provided by the super() instance:

class Bar(Foo):
    @classmethod
    def hello(cls):
        print 'hello, bar'
        super(Bar).__get__(cls, None).hello()

没有上下文的实例上的

super().__get__()有效地返回带有上下文集的新super()实例.在具有上下文.__get__()的实例上,仅返回self;它已经绑定.

super().__get__() on an instance without a context effectively returns a new super() instance with the context set. On an instance with a context .__get__() just returns self; it is already bound.

* 在Python 3中,从绑定方法内部调用不带参数的super()将使用调用框架隐式地发现类型和绑定对象,因此您不必在这种情况下,显式传递类型和对象参数.为此,Python 3实际上向方法添加了一个隐式__class__闭包变量.参见 PEP 3135

* In Python 3, calling super() without arguments from inside a bound method will use the calling frame to discover, implicitly, what the type and bound object are, so you no longer have to explicitly pass in the type and object arguments in that case. Python 3 actually adds a implicit __class__ closure variable to methods for this purpose. See PEP 3135 and Why is Python 3.x's super() magic?

这篇关于为什么类方法的super需要第二个参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆