在类方法中使用super
我正在尝试学习Python中的super()函数。
我以为自己已经掌握了这个概念,但在看到一个例子(2.6)后,我发现自己卡住了。
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告诉我的不可能的事情,因为它说do_something()应该用B的一个实例来调用。
5 个回答
我更新了这篇文章,让它更清晰一些:Python 属性和方法 # 超级
你上面用 classmethod 的例子展示了什么是类方法——它把类本身作为第一个参数,而不是实例。不过,你甚至不需要实例就可以调用这个方法,比如:
>>> class A(object):
... @classmethod
... def foo(cls):
... print cls
...
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>
在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.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
会作为第一个参数传给类A的do_your_stuff()
方法。
再说一遍:super(B, cls).do_your_stuff()
会调用A
的do_your_stuff
方法,并且cls
会作为第一个参数传入。为了让这个工作正常,A
的do_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
。
如果cls
是C
,那么super(cls, cls)
会在C.mro()
中查找在C
之后的类。
In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]
因为那个类是B
,当cls
是C
时,super(cls, cls).do_your_stuff()
总是调用B.do_your_stuff
。由于super(cls, cls).do_your_stuff()
是在B.do_your_stuff
内部被调用的,这样就会导致无限循环。
在Python3中,增加了0个参数的super
形式,这样super(B, cls)
可以被super()
替代,Python3会根据上下文判断在class B
的定义中,super()
相当于super(B, cls)
。
但是在任何情况下,super(cls, cls)
(或者出于类似原因,super(type(self), self)
)都是不正确的。