当前位置: 首页 > 面试题库 >

为什么Python 3.x的super()有魔力?

那利
2023-03-14
问题内容

在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

为了使这项工作有效,执​​行了一些编译时魔术,其结果是以下代码(重新绑定supersuper_)失败了:

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()在没有编译器帮助的情况下无法在运行时解析超类?在实际情况下,这种行为或其根本原因可能会咬一个粗心的程序员吗?

…,还有一个附带的问题:Python中是否还有其他函数,方法等示例,可以通过将它们重新绑定为其他名称来破坏它们吗?


问题答案:

super()添加了新的魔术行为,以避免违反DRY(请勿重复自己)原理,请参阅PEP 3135。必须通过将其引用为全局来显式地命名该类,这也容易产生与你自己发现的相同的重新绑定问题super()

class Foo(Bar):
    def baz(self):
        return super(Foo, self).baz() + 42

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

对于使用类装饰器的情况也是如此,其中装饰器返回一个新对象,该对象重新绑定了类名:

@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发起,他最初设想super成为关键字,并且使用单元格查找当前班级的想法也是他的想法。当然,使其成为关键字的想法是PEP初稿的一部分。

但是,实际上是Guido自己才放弃了“太不可思议”的关键字概念,而是提出了当前的实现方式。他预计使用其他名称super()可能会出现问题:

我的补丁使用了一种中间解决方案:假定你__class__每次使用名为的变量时都需要使用'super'。因此,如果你(全局)重新命名super,以supper和使用supper,但不能super,也不会不带参数的工作(但它仍然可以工作,如果你通过它要么 __class__或实际的类对象); 如果你有一个名为的不相关变量super,那么一切都会起作用,但是该方法将使用稍慢一些的用于单元变量的调用路径。

因此,最终,Guido自己宣布使用super关键字感觉不正确,并且提供一个魔术__class__单元是可以接受的折衷方案。

我同意该实现的神奇的,隐式的行为有些令人惊讶,但它super()是该语言中最常被错误使用的功能之一。只需看看 Internet上所有被误用super(type(self), self)super(self.__class__, self)调用的内容;如果从派生类调用了任何代码,最终都会遇到无限递归异常。至少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


 类似资料:
  • 以下Python3.x整数乘法的平均运算时间在1.66s到1.77s之间: 如果将替换为,则需要在和之间。怎么会呢? 另一方面,在Java中则相反:在Java中更快。Java测试链接:为什么在Java中2*(i*i)比2*i*i快? 我运行每个版本的程序10次,以下是结果。

  • 问题内容: 我试图了解何时以及如何在Python中正确使用super()(2.7.x或3.x) 在翻译告诉我怎么称呼它: 我了解在Python3.x中现在可以在类定义中使用super(),但是我不明白为什么不可能。或在类定义中。 我知道一定有原因,但是我找不到。对我来说,这些行等于或,并且行得通吗? 我认为即使在Python 3.x中,键入也是一个不错的快捷方式。 问题答案: 仅在Python 2

  • 基于此,我认为我应该完全开始在中使用

  • 问题内容: 最近,我开始使用Python3,它缺乏xrange的好处。 简单的例子: 1) Python2: 2) Python3: 结果分别是: 1) 1.53888392448 2) 3.215819835662842 这是为什么?我的意思是,为什么xrange被删除了?这是学习的好工具。对于初学者来说,就像我自己一样,就像我们都处在某个时刻。为什么要删除它?有人可以指出我正确的PEP,我找不

  • 问题内容: 当是重要的传球到了,为什么? 问题答案: 只有一种原因需要传递给: 当您要在构造函数中访问时。 通过: 未通过: 注意,通过或不通过,以有 没有影响 对以后的用途之外。也就是说,或事件处理程序 始终 可以访问它。 这是索菲·阿尔珀特(Sophie Alpert)对类似问题的回答中明确指出的。 建议使用“ 状态和生命周期,将本地状态添加到类,第2点”中的文档: 类组件应始终使用调用基本构

  • 我想知道为什么numpy中有一维的维度数组(length,1),也有一维的维数组(lendth,),没有第二个值。 我经常遇到这种情况,例如在使用< code>np.concatenate()时,这需要预先执行< code>reshape步骤(或者我可以直接使用< code > h stack /< code > v stack )。 我想不出这种行为可取的理由。有人能解释一下吗? 编辑:< br