在 Python 3.x 中,super()
可以不带参数调用:
class A(object):
def x(self):
print("Hey now")
class B(A):
def x(self):
super().x()
>>> B().x()
Hey now
为了完成这项工作,需要执行一些编译时魔法,其结果之一是以下代码(将 super
重新绑定(bind)到 super_
)失败:
super_ = super
class A(object):
def x(self):
print("No flipping")
class B(A):
def x(self):
super_().x()
>>> B().x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found
为什么 super()
在没有编译器帮助的情况下无法在运行时解析父类(super class)?是否存在这种行为或其根本原因可能会咬到粗心的程序员的实际情况?
...并且,作为一个附带问题:Python 中是否还有其他函数、方法等示例可以通过将它们重新绑定(bind)到不同的名称来破坏?
最佳答案
添加了新的魔法 super()
行为以避免违反 D.R.Y. (不要重复自己)原则,见PEP 3135 .必须通过将类作为全局引用来显式命名类也容易出现与 super()
本身相同的重新绑定(bind)问题:
class Foo(Bar):
def baz(self):
return super(Foo, self).baz() + 42
Spam = Foo
Foo = something_else()
Spam().baz() # liable to blow up
这同样适用于使用类装饰器,其中装饰器返回一个新对象,该对象重新绑定(bind)类名:
@class_decorator_returning_new_class
class Foo(Bar):
def baz(self):
# Now `Foo` is a *different class*
return super(Foo, self).baz() + 42
神奇的 super()
__class__
单元通过让您访问原始类对象很好地回避了这些问题。
PEP 由 Guido 启动,他是 initially envisioned super
becoming a keyword ,以及使用单元格查找当前类的想法was also his .当然,将其作为关键字的想法是 first draft of the PEP 的一部分。 .
然而,当时stepped away from the keyword idea as 'too magical' 实际上是Guido 本人。 ,而是提出当前的实现。他anticipated that using a different name for super()
could be a problem :
My patch uses an intermediate solution: it assumes you need
__class__
whenever you use a variable named'super'
. Thus, if you (globally) renamesuper
tosupper
and usesupper
but notsuper
, it won't work without arguments (but it will still work if you pass it either__class__
or the actual class object); if you have an unrelated variable namedsuper
, things will work but the method will use the slightly slower call path used for cell variables.
所以,最后是 Guido 自己宣称使用 super
关键字感觉不对,并且提供一个神奇的 __class__
单元格是一个可以接受的折衷方案.
我同意实现的神奇隐式行为有点令人惊讶,但 super()
是该语言中应用最多的函数之一。看看所有误用的super(type(self), self)
或 super(self.__class__, self)
在 Internet 上找到的调用;如果从派生类中调用了任何代码you'd end up with an infinite recursion exception .至少简化的 super()
调用没有参数,避免了 那个 问题。
至于重命名的super_
;只需在您的方法中引用 __class__
,它就会再次起作用。如果您在方法中引用 super
或 __class__
名称,则会创建单元格:
>>> super_ = super
>>> class A(object):
... def x(self):
... print("No flipping")
...
>>> class B(A):
... def x(self):
... __class__ # just referencing it is enough
... super_().x()
...
>>> B().x()
No flipping
https://stackoverflow.com/questions/19608134/