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



我正在使用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必须是类型的实例或亚型

这个问题似乎是由attrs(带有明确__slots__=()工作的未装修类),插槽(常规@attr.s-装修类工作)和普通super()调用(super(Derived, self) Works)的组合触发的。

我想了解super()的行为与显式super(Derived, self)版本的行为不同,因为文档说他们"做同样的事情"

super()通常依赖编译器提供一个 __class__闭合单元格,该单元格与类对象绑定到一个方法。在方法中使用名称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参数是从本地名称空间中获取的)。

但是, attr在指定要使用 __slots__时会生成新类对象 ;事实之后,您无法在类中添加插槽,因此创建了一个新的类对象,以取代您装饰的一个。

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查找为全局,找到新生成的类,因此工作。

我更详细介绍super()如何无参数的工作,为什么,为什么Python 3.x的Super()魔术?

这是在跟踪器中的第102期报道的, fixed 通过使用一些ctypes黑客更改闭合。此修复程序将是即将发布的17.3版本的一部分。

最新更新