gpt4 book ai didi

python - super() 和显式 super(Cl,self) 之间有什么区别(带有 __slots__ 和 attrs)

转载 作者:行者123 更新时间:2023-11-28 18:19:27 24 4
gpt4 key购买 nike

我正在使用 attrs python 包,结合继承和插槽。我想从派生方法中调用父类的方法。问题演示如下:

import attr

@attr.s(slots=True)
class Base():
def meth(self):
print("hello")

@attr.s(slots=True)
class Derived(Base):
def meth(self):
super().meth()
print("world")

d = Derived()
d.meth()

我得到:

TypeError: super(type, obj): obj must be an instance or subtype of type

问题似乎是由 attr(具有显式 __slots__=() 工作的未修饰类)、插槽(常规 @attr.s 修饰类)的组合触发的工作)和普通的 super() 调用(super(Derived, self) 工作)。

我想了解 super() 与显式 super(Derived, self) 版本的行为有何不同,因为 documentation说他们“做同样的事”

最佳答案

super() 通常依赖于编译器提供一个 __class__ 闭包单元,它绑定(bind)到派生方法的类对象。当您在方法中使用名称 super() 时(或者如果您使用 __class__),就会创建闭包:

>>> class Foo(object):
... def bar(self):
... super() # just using super or __class__ is enough
...
>>> Foo.bar.__closure__[0].cell_contents
<class '__main__.Foo'>
>>> Foo.bar.__closure__[0].cell_contents is Foo
True

那个闭包让 super() 可以在没有参数的情况下工作(self 参数取自本地命名空间)。

但是,当您指定要使用 __slots__ 时,attr 会生成一个新类对象;你不能在事后给类添加槽,所以 new class object is created取代你装饰的那个。

附在meth上的闭包是原来的预修饰类,与新生成的类不是同一个类对象:

>>> Derived.meth.__closure__[0].cell_contents
<class '__main__.Derived'>
>>> Derived.meth.__closure__[0].cell_contents is Derived
False

这打破了 super() 的期望,使得无法使用 0 参数变体。 super(Derived, self) 变体在调用时明确查找名称 Derived 作为全局名称,找到新生成的类,这样就可以了。

我在 Why is Python 3.x's super() magic? 中详细介绍了不带参数的 super() 的工作原理以及原因。

这被报告为 issue #102在跟踪器中,并通过用一些 ctypes hackery 改变闭包来修复 .此修复将成为即将发布的 17.3 版本的一部分。

关于python - super() 和显式 super(Cl,self) 之间有什么区别(带有 __slots__ 和 attrs),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46159210/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com