在类方法中使用super


82

我正在尝试学习Python中的super()函数。

我以为我已经掌握了它,直到我看完这个示例(2.6)并发现自己陷入困境。

http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#super-with-classmethod-example

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 9, in do_something
    do_something = classmethod(do_something)
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)
>>>

当我在示例之前阅读此行时,这不是我期望的:

如果使用的是类方法,则没有实例可以调用super。对我们来说幸运的是,即使类型是第二个参数,super也可以工作。---可以将类型直接传递给super,如下所示。

Python不能通过说do_something()应该与B的实例一起调用来告诉我。


Answers:


98

有时,文本必须更多地阅读,以体现想法的趣味而不是细节。这是其中一种情况。

链接的页面中,示例2.5、2.6和2.7都应使用一种方法do_your_stuff。(即do_something应更改为do_your_stuff。)

此外,正如Ned Deily指出的那样A.do_your_stuff必须是一种类方法。

class A(object):
    @classmethod
    def do_your_stuff(cls):
        print 'This is A'

class B(A):
    @classmethod
    def do_your_stuff(cls):
        super(B, cls).do_your_stuff()

B.do_your_stuff()

super(B, cls).do_your_stuff 返回一个绑定方法(请参见脚注2)。由于 cls已作为的第二个参数传递super(),因此它将cls绑定到返回的方法。换句话说,cls被作为第一个参数传递给do_your_stuff()类A的方法。

重申:super(B, cls).do_your_stuff()导致Ado_your_stuff方法cls作为第一个参数传递。为了让这工作,Ado_your_stuff必须是一个类的方法。链接页面没有提及,但是确实如此。

PS。do_something = classmethod(do_something)是制作类方法的旧方法。新的方法是使用@classmethod装饰器。


请注意,super(B, cls)不能用代替super(cls, cls)。这样做可能导致无限循环。例如,

class A(object):
    @classmethod
    def do_your_stuff(cls):
        print('This is A')

class B(A):
    @classmethod
    def do_your_stuff(cls):
        print('This is B')
        # super(B, cls).do_your_stuff()  # CORRECT
        super(cls, cls).do_your_stuff()  # WRONG

class C(B):
    @classmethod
    def do_your_stuff(cls):
        print('This is C')
        # super(C, cls).do_your_stuff()  # CORRECT
        super(cls, cls).do_your_stuff()  # WRONG

C.do_your_stuff()

会提高RuntimeError: maximum recursion depth exceeded while calling a Python object

如果clsC,则super(cls, cls)搜索C.mro()后面的类C

In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]

由于该类是B,何时clsCsuper(cls, cls).do_your_stuff() 总是调用B.do_your_stuff。由于super(cls, cls).do_your_stuff()在内部被调用B.do_your_stuff,您最终将B.do_your_stuff陷入无限循环。

在Python3中,添加了0参数形式的super,因此super(B, cls)可以替换为super(),Python3将根据上下文确定super()在的定义中class B应等价于super(B, cls)

但是在任何情况下super(cls, cls)(或出于类似原因super(type(self), self))都不正确。


使用super(cls,cls)有陷阱吗?
乔治·穆特索普洛斯

2
@GeorgeMoutsopoulos:super(cls, cls)几乎可以肯定是一个错误。我已经编辑了上面的帖子以解释原因。
unutbu

37

在Python 3中,您可以跳过为super

class A:
    @classmethod
    def f(cls):
        return "A's f was called."

class B(A):
    @classmethod
    def f(cls):
        return super().f()

assert B.f() == "A's f was called."

如果这个特定问题是专门针对Python 2的,那么这个答案可能会转移到另一个问题(很难知道,因为链接的网站CafePy不再可用)。
Tankobot

在我的项目中,这对我不起作用。它给RuntimeError: super(): no arguments
madtyn

4

我已经更新了文章,使文章更加清晰:Python属性和方法#超级

您上面使用classmethod的示例显示了什么是类方法-它通过类本身而不是实例作为第一个参数。但是您甚至不需要实例来调用该方法,例如:

>>> class A(object):
...     @classmethod
...     def foo(cls):
...         print cls
... 
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>

2

网页中的示例似乎已发布。您是否也do_something为超类创建了一个方法,但没有将其纳入类方法?这样的事情会给你这个错误:

>>> class A(object):
...     def do_something(cls):
...         print cls
... #   do_something = classmethod(do_something)
... 
>>> class B(A):
...     def do_something(cls):
...         super(B, cls).do_something()
...     do_something = classmethod(do_something)
... 
>>> B().do_something()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in do_something
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)

不,我的A类看起来像这样:类A(对象):def do_your_stuff(self):打印“这是A”发布时是否需要“类A”?(与do_something = classmethod(do_something))?我觉得该文件没有透露任何信息..
dza

1
superB do_something方法中调用的全部要点是在其超类之一中调用该名称的方法。如果A(或Object)中没有一个,则B()。do_something()调用将失败super object has no attribute do_something。〜unutbu正确地指出文档中的示例是错误的。
内德·迪利2009年

0

由于这个漂亮的网站和可爱的社区,我想我现在已经明白了这一点。

如果您不介意,如果我在类方法(我现在想完全理解)上错了,请纠正我:


# EXAMPLE #1
>>> class A(object):
...     def foo(cls):
...             print cls
...     foo = classmethod(foo)
... 
>>> a = A()
>>> a.foo()
# THIS IS THE CLASS ITSELF (__class__)
class '__main__.A'

# EXAMPLE #2
# SAME AS ABOVE (With new @decorator)
>>> class A(object):
...     @classmethod
...     def foo(cls):
...             print cls
... 
>>> a = A()
>>> a.foo()
class '__main__.A'

# EXAMPLE #3
>>> class B(object):
...     def foo(self):
...             print self
... 
>>> b = B()
>>> b.foo()
# THIS IS THE INSTANCE WITH ADDRESS (self)
__main__.B object at 0xb747a8ec
>>>

我希望这个图显示..


:对于classmethods的解释,也许你会发现这是很有帮助的stackoverflow.com/questions/1669445/...
unutbu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.