[英]Using super with a class method
I'm trying to learn the super() function in Python. 我正在尝试学习Python中的super()函数。
I thought I had a grasp of it until I came over this example (2.6) and found myself stuck. 我以为我掌握了它,直到我看到这个例子(2.6)并发现自己卡住了。
http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#super-with-classmethod-example 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)
>>>
It wasn't what I expected when I read this line right before the example: 当我在示例之前读到这一行时,这不是我的预期:
If we're using a class method, we don't have an instance to call super with.如果我们使用类方法,我们没有一个实例来调用super。 Fortunately for us, super works even with a type as the second argument.
幸运的是,对于我们来说,super甚至可以使用类型作为第二个参数。 --- The type can be passed directly to super as shown below.
---类型可以直接传递给super,如下所示。
Which is exactly what Python tells me is not possible by saying that do_something() should be called with an instance of B. 通过说do_something()应该用B的实例调用,这正是Python告诉我的不可能。
Sometimes texts have to be read more for the flavor of the idea rather than for the details. 有时,文字必须更多地阅读,而不是细节。 This is one of those cases.
这是其中一个案例。
In the linked page , Examples 2.5, 2.6 and 2.7 should all use one method, do_your_stuff
. 在链接页面中 ,示例
do_your_stuff
和2.7都应使用一个方法do_your_stuff
。 (That is, do_something
should be changed to do_your_stuff
.) (也就是说,
do_something
应该更改为do_your_stuff
。)
In addition, as Ned Deily pointed out , A.do_your_stuff
has to be a class method. 另外,正如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
returns a bound method (see footnote 2 ). super(B, cls).do_your_stuff
返回一个绑定方法(见脚注2 )。 Since cls
was passed as the second argument to super()
, it is cls
that gets bound to the returned method. 由于
cls
作为第二个参数传递给super()
,因此它是绑定到返回方法的cls
。 In other words, cls
gets passed as the first argument to the method do_your_stuff()
of class A. 换句话说,
cls
作为A类方法do_your_stuff()
的第一个参数传递。
To reiterate: super(B, cls).do_your_stuff()
causes A
's do_your_stuff
method to be called with cls
passed as the first argument. 重申
super(B, cls).do_your_stuff()
: super(B, cls).do_your_stuff()
会导致调用A
的do_your_stuff
方法,并将cls
作为第一个参数传递。 In order for that to work, A
's do_your_stuff
has to be a class method. 为了实现这一点,
A
的do_your_stuff
必须是一个类方法。 The linked page doesn't mention that, but that is definitively the case. 链接页面没有提到这一点,但确实如此。
PS. PS。
do_something = classmethod(do_something)
is the old way of making a classmethod. do_something = classmethod(do_something)
是制作classmethod的旧方法。 The new(er) way is to use the @classmethod decorator. 新的(呃)方法是使用@classmethod装饰器。
Note that super(B, cls)
can not be replaced by super(cls, cls)
. 请注意,
super(B, cls)
不能被super(cls, cls)
替换。 Doing so could lead to infinite loops. 这样做可能会导致无限循环。 For example,
例如,
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()
will raise RuntimeError: maximum recursion depth exceeded while calling a Python object
. 将引发
RuntimeError: maximum recursion depth exceeded while calling a Python object
。
If cls
is C
, then super(cls, cls)
searches C.mro()
for the class that comes after C
. 如果
cls
是C
,则super(cls, cls)
C.mro()
搜索C
之后的类。
In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]
Since that class is B
, when cls
is C
, super(cls, cls).do_your_stuff()
always calls B.do_your_stuff
. 由于该类是
B
,当cls
是C
, super(cls, cls).do_your_stuff()
总是调用B.do_your_stuff
。 Since super(cls, cls).do_your_stuff()
is called inside B.do_your_stuff
, you end up calling B.do_your_stuff
in an infinite loop. 由于在
B.do_your_stuff
调用了super(cls, cls).do_your_stuff()
,因此最终在无限循环中调用B.do_your_stuff
。
In Python3, the 0-argument form of super
was added so super(B, cls)
could be replaced by super()
, and Python3 will figure out from context that super()
in the definition of class B
should be equivalent to super(B, cls)
. 在Python3中,添加了0参数形式的
super
,因此super(B, cls)
可以被super()
替换,而Python3将从上下文中找出class B
定义中的super()
应该等于super(B, cls)
。
But in no circumstance is super(cls, cls)
(or for similar reasons, super(type(self), self)
) ever correct. 但在任何情况下,
super(cls, cls)
(或类似的原因, super(type(self), self)
)都是正确的。
In Python 3, you can skip specifying arguments for super
, 在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."
I've updated the article to make it a bit clearer: Python Attributes and Methods # Super 我已经更新了这篇文章,使其更加清晰: Python属性和方法#Super
Your example using classmethod above shows what a class method is - it passes the class itself instead of the instance as the first parameter. 上面使用classmethod的示例显示了一个类方法 - 它将类本身而不是实例作为第一个参数传递。 But you don't even need an instance to call the method, for eg:
但是你甚至不需要一个实例来调用该方法,例如:
>>> class A(object):
... @classmethod
... def foo(cls):
... print cls
...
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>
The example from the web page seems to work as published. 网页上的示例似乎已发布。 Did you create a
do_something
method for the superclass as well but not make it into a classmethod? 您是否为超类创建了
do_something
方法,但没有将其变为类方法? Something like this will give you that error: 像这样的东西会给你这个错误:
>>> 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)
I think I've understood the point now thanks to this beatiful site and lovely community. 我想我已经理解了这一点,感谢这个美丽的网站和可爱的社区。
If you don't mind please correct me if I'm wrong on classmethods (which I am now trying to understand fully): 如果你不介意的话请纠正我,如果我在课堂方法上错了(我现在试图完全理解):
# 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
>>>
I hope this illustration shows .. 我希望这个插图显示..
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.