Nio*_*bos 4 python super python-3.x python-attrs
我正在使用attrspython 包,结合继承和插槽。我想从派生方法中调用父类的方法。该问题演示如下:
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()
Run Code Online (Sandbox Code Playgroud)
我得到:
TypeError: super(type, obj): obj 必须是 type 的实例或子类型
__slots__=()该问题似乎是由 attrs(具有显式工作的未修饰类)、插槽(常规@attr.s修饰类工作)和普通super()调用(工作)的组合触发的super(Derived, self)。
我想了解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
Run Code Online (Sandbox Code Playgroud)
该闭包允许super()在没有参数的情况下工作(self参数取自本地名称空间)。
但是,当您指定要使用时,attr会生成一个新的类对象__slots__;您无法在事后向类添加插槽,因此会创建一个新的类对象来替换您装饰的对象。
附加的闭包meth是原始的预装饰类,而不是与新生成的类相同的类对象:
>>> Derived.meth.__closure__[0].cell_contents
<class '__main__.Derived'>
>>> Derived.meth.__closure__[0].cell_contents is Derived
False
Run Code Online (Sandbox Code Playgroud)
这打破了预期super(),使得无法使用 0 参数变体。该super(Derived, self)变体在调用时显式地将名称查找Derived为全局名称,找到新生成的类,因此可以工作。
我在《Python 3.x 的 super() 为何如此神奇?》中更详细地介绍了super()无参数的工作原理及其原因。
这在跟踪器中被报告为问题#102 ,并通过使用一些黑客技术改变关闭来修复。此修复将成为即将发布的 17.3 版本的一部分。ctypes
| 归档时间: |
|
| 查看次数: |
411 次 |
| 最近记录: |