super() 和显式 super(Cl,self) 之间有什么区别(使用 __slots__ 和 attrs)
What is the difference between super() and explicit super(Cl,self) (with __slots__ and attrs)
我正在使用 attrs
python 包,结合继承和插槽。我想从派生方法中调用父 class 的方法。问题演示如下:
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
问题似乎是由属性(未修饰的 classes 与显式 __slots__=()
工作)、槽(常规 @attr.s
-修饰的 classes工作)和普通的 super()
调用(super(Derived, self)
工作)。
我想了解 super()
与显式 super(Derived, self)
版本的行为有何不同,因为 documentation 表示它们 "do the same thing"
super()
通常依赖于编译器提供一个 __class__
闭包单元,该单元绑定到 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
参数取自本地命名空间)。
但是,当您指定要使用 __slots__
时,attr
会生成一个 新的 class 对象 ;你不能在事后向 class 添加插槽,因此 new class object is created 会替换你装饰的插槽。
附加到 meth
的闭包是原始的预装饰 class 而不是与新生成的 class 对象相同的 class:
>>> Derived.meth.__closure__[0].cell_contents
<class '__main__.Derived'>
>>> Derived.meth.__closure__[0].cell_contents is Derived
False
这打破了 super()
的预期,因此无法使用 0 参数变体。 super(Derived, self)
变体在调用时明确地将名称 Derived
查找为全局名称,找到新生成的 class,如此有效。
我在 Why is Python 3.x's super() magic?
中详细介绍了不带参数的 super()
的工作原理以及原因
这被报告为 issue #102 in the tracker, and fixed by altering the closure with some ctypes
hackery。此修复将成为即将发布的 17.3 版本的一部分。
我正在使用 attrs
python 包,结合继承和插槽。我想从派生方法中调用父 class 的方法。问题演示如下:
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
问题似乎是由属性(未修饰的 classes 与显式 __slots__=()
工作)、槽(常规 @attr.s
-修饰的 classes工作)和普通的 super()
调用(super(Derived, self)
工作)。
我想了解 super()
与显式 super(Derived, self)
版本的行为有何不同,因为 documentation 表示它们 "do the same thing"
super()
通常依赖于编译器提供一个 __class__
闭包单元,该单元绑定到 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
参数取自本地命名空间)。
但是,当您指定要使用 __slots__
时,attr
会生成一个 新的 class 对象 ;你不能在事后向 class 添加插槽,因此 new class object is created 会替换你装饰的插槽。
附加到 meth
的闭包是原始的预装饰 class 而不是与新生成的 class 对象相同的 class:
>>> Derived.meth.__closure__[0].cell_contents
<class '__main__.Derived'>
>>> Derived.meth.__closure__[0].cell_contents is Derived
False
这打破了 super()
的预期,因此无法使用 0 参数变体。 super(Derived, self)
变体在调用时明确地将名称 Derived
查找为全局名称,找到新生成的 class,如此有效。
我在 Why is Python 3.x's super() magic?
中详细介绍了不带参数的super()
的工作原理以及原因
这被报告为 issue #102 in the tracker, and fixed by altering the closure with some ctypes
hackery。此修复将成为即将发布的 17.3 版本的一部分。