为何int子类实例修改__class__报错而float子类无此问题?
Python中int与float子类的__class__赋值行为差异解析
核心原因:CPython底层结构的本质区别
CPython对int和float的底层C实现完全不同,直接导致了它们的子类在切换__class__时的行为差异:
1. int子类报错的根源:变长对象的布局不兼容
int对应的C结构PyLongObject是变长对象:它靠ob_size字段跟踪整数的位数,支持任意大小的整数,内存占用会随数值大小变化。- 当你定义不带
__slots__的int子类时,实例会自动生成__dict__和__weakref__来存储额外属性,但由于PyLongObject的变长特性,不同int子类的实例内存布局无法保证一致——哪怕两个子类代码完全一样,CPython也判定它们的结构偏移存在差异,切换__class__时就会抛出TypeError。 - 给int子类加上
__slots__ = ()后,会禁止实例创建__dict__,此时子类实例的内存布局和原生int完全对齐,不同int子类的实例结构一致,__class__赋值就能正常执行。
2. float子类无需__slots__的原因:定长对象的布局一致性
float对应的C结构PyFloatObject是定长对象:它的内存结构固定,只包含一个双精度浮点数的ob_fval字段,内存占用始终是固定字节数。- 哪怕float子类没定义
__slots__,实例生成的__dict__和__weakref__存储区的位置是统一固定的——所有float子类的实例都遵循“固定的PyFloatObject结构 + 统一的扩展存储区”的布局,结构偏移完全一致。 - 这种一致的内存布局让不同float子类的实例之间可以安全切换
__class__,不会触发布局不兼容的错误。
内容的提问来源于stack exchange,提问作者Alexander Myasnikov
相关产品推荐
相关产品推荐

