【问题标题】:Using super with a class method将 super 与类方法一起使用
【发布时间】:2010-12-21 11:47:21
【问题描述】:

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

【问题讨论】:

标签: python class object super class-method


【解决方案1】:

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

linked page 中,示例 2.5、2.6 和 2.7 都应该使用一种方法,do_your_stuff。 (即do_something要改成do_your_stuff。)

另外,作为Ned Deily pointed outA.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 返回一个 bound 方法(参见footnote 2)。由于cls 作为第二个参数传递给super(),因此绑定到返回方法的是cls。换句话说,cls 作为第一个参数传递给类 A 的方法 do_your_stuff()

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

附言。 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()B.do_your_stuff 内部被调用,你最终会在无限循环中调用B.do_your_stuff

在 Python3 中,添加了 0-argument form of super,因此 super(B, cls) 可以替换为 super(),并且 Python3 将根据上下文确定 class B 定义中的 super() 应该等同于 super(B, cls)

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

【讨论】:

  • 使用 super(cls, cls) 有什么陷阱吗?
  • @GeorgeMoutsopoulos: super(cls, cls) 几乎可以肯定是一个错误。我已经编辑了上面的帖子来解释原因。
【解决方案2】:

在 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 不再可用)。
  • 在我的项目中它不适合我。它正在给RuntimeError: super(): no arguments
【解决方案3】:

我已更新文章以使其更清晰: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'>

【讨论】:

    【解决方案4】:

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

    如果你不介意我在类方法上的错误(我现在正试图完全理解),请纠正我:

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

    我希望这个插图能说明..

    【讨论】:

    【解决方案5】:

    网页中的示例似乎与已发布的一样。您是否也为超类创建了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 类看起来像这样: class A(object): def do_your_stuff(self): print "this is A" 是否有必要像您发布的那样拥有“class A”? (用do_something = classmethod(do_something))?我觉得该文件没有说明任何关于此的内容..
    • B do_something 方法中super 调用的全部意义在于在其超类之一中调用该名称的方法。如果 A(或 Object)中没有一个,则 B().do_something() 调用将失败并显示super object has no attribute do_something。 ~unutbu 正确指出文档中的示例有问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 1970-01-01
    • 2018-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多