92

我正在尝试学习 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 告诉我的,通过说应该用 B 的实例调用 do_something() 是不可能的。

4

5 回答 5

112

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

链接页面中,示例 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()导致A' 的do_your_stuff方法被调用,cls并作为第一个参数传递。为了使它起作用,A's do_your_stuff必须是一个类方法。链接页面没有提到这一点,但确实如此。

PS。do_something = classmethod(do_something)是制作类方法的旧方法。新的(er)方法是使用 @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()被调用 inside 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))都不正确。

于 2009-11-30T04:22:56.930 回答
50

在 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."
于 2017-11-12T08:57:08.993 回答
4

我更新了文章以使其更清晰:Python Attributes and Methods # Super

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

>>> class A(object):
...     @classmethod
...     def foo(cls):
...         print cls
... 
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>
于 2009-12-03T06:11:25.337 回答
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)
于 2009-11-30T00:10:37.617 回答
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
>>>

我希望这个插图显示..

于 2009-11-30T17:01:05.287 回答