为什么 Python 3.x 的 super() 如此神奇?

2025-01-17 09:23:00
admin
原创
100
摘要:问题描述:在 Python 3.x 中,super()可以不带参数调用:class A(object): def x(self): print("Hey now") class B(A): def x(self): super().x()...

问题描述:

在 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 中是否还有其他函数、方法等的示例,可以通过将它们重新绑定到不同的名称来破坏?


解决方案 1:

添加新的魔法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'。因此,如果您(全局)重命名supersupper并使用supper但不使用super,它将无法在没有参数的情况下工作(但如果您传递它
__class__或实际的类对象,它仍然可以工作);如果您有一个名为 的不相关变量super,事情将正常工作,但该方法将使用用于单元格变量的稍慢的调用路径。

所以,最后还是 Guido 自己宣称使用super关键字感觉不对,而提供魔法__class__单元是一个可以接受的折衷方案。

我同意,该实现的神奇、隐式行为有些令人惊讶,但super()它是该语言中最常被误用的函数之一。只需看看互联网上发现的所有误用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
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3016  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1880  
  项目里程碑计划图作为项目管理中的关键工具,为项目的推进提供了清晰的路线图和重要的时间节点标识。它不仅有助于项目团队明确目标、合理安排资源,还能让项目相关方对项目进度有直观的了解。然而,在项目实施过程中,变更往往不可避免。无论是客户需求的变化、市场环境的波动,还是技术难题的出现,都可能导致项目偏离原计划。如何利用项目里程...
敏捷冲刺是什么   0  
  项目里程碑计划图作为项目管理中的关键工具,贯穿于项目的全生命周期,在项目收尾阶段更是发挥着不可替代的重要作用。它犹如航海中的灯塔,为项目的最终完成指引方向,确保项目能够有条不紊地驶向成功的彼岸。在项目收尾阶段,各种任务繁杂且相互关联,稍有不慎就可能导致项目功亏一篑。而项目里程碑计划图凭借其独特的功能和价值,成为保障项目...
燃尽图怎么画   0  
  敏捷开发模式在软件开发领域得到了广泛应用,它强调快速迭代、团队协作以及对变化的快速响应。在敏捷开发过程中,测试环节至关重要,尤其是跨功能测试策略,它能够确保各个功能模块之间的协同工作正常,提升软件整体质量。跨功能测试关注的是不同功能组件、不同团队所负责部分之间的交互,旨在发现集成过程中出现的问题,避免在后期阶段才暴露出...
敏捷开发与传统开发区别   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用