在 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. (Don't Repeat Yourself)原理,见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 的一部分。 .
然而,实际上是 Guido 自己stepped away from the keyword idea as 'too magical' ,而不是提出当前的实现。他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
关于python - 为什么 Python 3.x 的 super() 如此神奇?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48691652/