使用super与类方法

dez*_*zza 68 python class object super class-method

我正在尝试学习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)
>>>
Run Code Online (Sandbox Code Playgroud)

当我在示例之前读到这一行时,这不是我的预期:

如果我们使用类方法,我们没有一个实例来调用super.幸运的是,对于我们来说,super甚至可以使用类型作为第二个参数.---类型可以直接传递给super,如下所示.

通过说do_something()应该用B的实例调用,这正是Python告诉我的不可能.

unu*_*tbu 83

有时,文字必须更多地阅读,而不是细节.这是其中一个案例.

链接页面中,示例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()
Run Code Online (Sandbox Code Playgroud)

super(B, cls).do_your_stuff 返回一个绑定方法(见脚注2).因为 cls作为第二个参数传递super(),所以它cls被绑定到返回的方法.换句话说,cls作为方法的第一个参数传递do_your_stuff().

因此,调用super(B, cls).do_your_stuff()cause 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()
Run Code Online (Sandbox Code Playgroud)

会提高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]
Run Code Online (Sandbox Code Playgroud)

由于该类是B,当clsC,super(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 Bsuper(B, cls)

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

  • @GeorgeMoutsopoulos:`super(cls, cls)` 几乎肯定是一个错误。我已经编辑了上面的帖子来解释原因。 (3认同)

Tan*_*bot 20

在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."
Run Code Online (Sandbox Code Playgroud)

  • 它在我的项目中对我不起作用。它给出了“RuntimeError:super():没有参数” (3认同)