我正在使用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版本的一部分。