我正在尝试学习 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() ,这正是不可能的。

有帮助吗?

解决方案

有时,必须更多地阅读文本才能了解想法的风格,而不是细节。这是其中之一。

在里面 链接页面, ,示例2.5、2.6和2.7都应该使用一种方法, do_your_stuff. 。(那是, do_something 应该改为 do_your_stuff.)

此外,如 内德·戴利指出, 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 必须是一个类方法。链接页面没有提及这一点,但绝对是这种情况。

附言。 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, , 什么时候 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 B 应该等于 super(B, cls).

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

其他提示

在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属性和方法#Super

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

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

网页上的示例似乎已发布。您是否为超类创建了 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)

我想我现在已经明白了这一点,感谢这个美丽的网站和可爱的社区。

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


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

我希望这张插图能够显示..

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top