覆盖 __class__ 引发 TypeError
Overwriting __class__ raises TypeError
我正在尝试扩展用 C 编写的模块 class 的功能,方法是从 class 派生并覆盖/添加某些方法*。
问题是他的模块创建了 class 我试图在不同地方扩展的实例。因此,我需要创建一个转换方法,将模块提供的基础 class 转换为我自己的具有附加功能的派生 class。
这是我尝试过的方法:
class Derived(Base):
@classmethod
def cast(cls, obj: Base):
obj.__class__ = cls
此方法适用于我自己创建的 class 层次结构 - 但是它在我使用的模块中失败,抛出以下异常:
TypeError: __class__ assignment only supported for heap types or ModuleType subclasses
我很难找到有关此异常的官方信息。任何信息都有帮助,我什至会接受 hacky 解决方案,只要它们是干净的并且完全模仿我正在寻找的行为。
* 我要扩展的 class 是包 pygame
.
内的 Surface
__class__
属性在可接受的范围内一直受到限制,Python 类 可以比 C 中定义的类型灵活得多。
例如,__slots__
section in the datamodel documentation 状态:
__class__
assignment works only if both classes have the same __slots__
.
并且同一文档调用 instance.__class__
attribute 只读:
The implementation adds a few special read-only attributes to several object types, where they are relevant.
所以__class__
其实本来就不是可写的,但是已经用了很长时间了,非常有用属性。
现在,在您的情况下,不允许分配,因为目标实例的类型不会在堆上分配对象(进程内存区域会增长以容纳任意数量的对象,它是分配 most Python 对象的地方)。未在堆上分配的对象的管理方式不同(例如,不受引用计数的影响),如果您更改了它们的类型,它们将突然需要以不同方式进行管理。目前不支持。
在 Python 3.5 候选版本中是 briefly supported,允许在 模块 上设置 __class__
,但一旦它被适得其反发现可以改变内部不可变值的类型:
class MyInt(int):
# lets make ints mutable!
(1).__class__ = MyInt
1
是低价的 interned value, so now all use of the integer 1
everywhere in the Python program has been changed. Not what you want, especially if you are re-using interpreter memory across multiple processes the way the Google App Engine does! See issue #24912。
但这就是异常中特别提到模块实例的原因,参见Customising module attribute access。
您必须找到其他途径来解决您的问题。例如,也许您的特定问题可以通过 包装 某些使用 __getattr__
将属性代理到包装实例的实例来解决。
我正在尝试扩展用 C 编写的模块 class 的功能,方法是从 class 派生并覆盖/添加某些方法*。
问题是他的模块创建了 class 我试图在不同地方扩展的实例。因此,我需要创建一个转换方法,将模块提供的基础 class 转换为我自己的具有附加功能的派生 class。
这是我尝试过的方法:
class Derived(Base):
@classmethod
def cast(cls, obj: Base):
obj.__class__ = cls
此方法适用于我自己创建的 class 层次结构 - 但是它在我使用的模块中失败,抛出以下异常:
TypeError: __class__ assignment only supported for heap types or ModuleType subclasses
我很难找到有关此异常的官方信息。任何信息都有帮助,我什至会接受 hacky 解决方案,只要它们是干净的并且完全模仿我正在寻找的行为。
* 我要扩展的 class 是包 pygame
.
Surface
__class__
属性在可接受的范围内一直受到限制,Python 类 可以比 C 中定义的类型灵活得多。
例如,__slots__
section in the datamodel documentation 状态:
__class__
assignment works only if both classes have the same__slots__
.
并且同一文档调用 instance.__class__
attribute 只读:
The implementation adds a few special read-only attributes to several object types, where they are relevant.
所以__class__
其实本来就不是可写的,但是已经用了很长时间了,非常有用属性。
现在,在您的情况下,不允许分配,因为目标实例的类型不会在堆上分配对象(进程内存区域会增长以容纳任意数量的对象,它是分配 most Python 对象的地方)。未在堆上分配的对象的管理方式不同(例如,不受引用计数的影响),如果您更改了它们的类型,它们将突然需要以不同方式进行管理。目前不支持。
在 Python 3.5 候选版本中是 briefly supported,允许在 模块 上设置 __class__
,但一旦它被适得其反发现可以改变内部不可变值的类型:
class MyInt(int):
# lets make ints mutable!
(1).__class__ = MyInt
1
是低价的 interned value, so now all use of the integer 1
everywhere in the Python program has been changed. Not what you want, especially if you are re-using interpreter memory across multiple processes the way the Google App Engine does! See issue #24912。
但这就是异常中特别提到模块实例的原因,参见Customising module attribute access。
您必须找到其他途径来解决您的问题。例如,也许您的特定问题可以通过 包装 某些使用 __getattr__
将属性代理到包装实例的实例来解决。