使用super与类方法

时间:2009-11-29 23:45:59

标签: 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)
>>>

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

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

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

5 个答案:

答案 0 :(得分:76)

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

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 返回绑定方法(请参阅footnote 2)。由于cls作为第二个参数传递给super(),因此cls绑定到返回的方法。换句话说,cls作为方法do_you_stuff()的第一个参数传递。

因此super(B, cls).do_your_stuff()会导致A的{​​{1}}方法 调用do_your_stuff作为第一个参数传递。为了实现这一点,cls A必须是类方法。链接页面没有提到, 但这是真的。

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


请注意,do_something = classmethod(do_something)无法替换为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 objectcls,则C会在super(cls, cls)之后搜索C.mro()之后的课程。

C

由于该课程为In [161]: C.mro() Out[161]: [__main__.C, __main__.B, __main__.A, object] ,当Bcls时,C 始终会调用super(cls, cls).do_your_stuff()。由于在B.do_your_stuff内调用super(cls, cls).do_your_stuff(),您最终会在无限循环中调用B.do_your_stuff

在Python3中,添加了0-argument form of super,因此B.do_your_stuff可以替换为super(B, cls),Python3将根据super()定义super()应该等同于class B

但在任何情况下super(B, cls)(或由于类似原因,super(cls, cls))都不会更正。

答案 1 :(得分:11)

在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."

答案 2 :(得分: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'>

答案 3 :(得分: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)

答案 4 :(得分: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
>>>

我希望这个插图显示..