使用slots=True的dataclass调用super()触发TypeError的原因及解决
问题描述
我有一个带类似getter方法的dataclass,无slots时代码可正常运行:
from dataclasses import dataclass @dataclass() class A: def get_data(self): # get some values from object's fields # do some calculations return "a calculated value" @dataclass() class B(A): def get_data(self): data = super().get_data() return data + " (modified)" b = B() print(b.get_data()) # a calculated value (modified)
但给dataclass添加slots=True后会触发TypeError:
from dataclasses import dataclass @dataclass(slots=True) class A: def get_data(self): return "a calculated value" @dataclass(slots=True) class B(A): def get_data(self): data = super().get_data() return data + " (modified)" b = B() print(b.get_data()) # TypeError: super(type, obj): obj must be an instance or subtype of type
改用显式指定类的旧式super(B, self)写法后,错误消失:
from dataclasses import dataclass @dataclass(slots=True) class A: def get_data(self): return "a calculated value" @dataclass(slots=True) class B(A): def get_data(self): data = super(B, self).get_data() return data + " (modified)" b = B() print(b.get_data()) # a calculated value (modified)
问题原因
- 使用
@dataclass(slots=True)时,Python会生成仅包含指定槽位的类结构,子类默认不会自动继承父类的槽位,这会改变类的内部继承结构。 - PEP 3135的无参数
super()依赖函数定义时绑定的__class__闭包变量,但带slots=True的dataclass子类在生成过程中,会导致这个闭包变量的绑定异常,使得无参数super()无法正确识别当前类与实例的关系,从而抛出类型错误。 - 显式传递
super(B, self)时,直接指定了类和实例,绕过了闭包变量的问题,因此能正常运行。
正确解决方式
有两种可靠的解决办法:
- 显式指定
super参数:直接使用super(B, self).get_data(),这种写法虽然不符合PEP 3135的简化风格,但在该场景下稳定有效,不存在兼容性问题。 - 让子类继承父类槽位:在子类B中显式声明继承父类的槽位,修改后的代码如下:
from dataclasses import dataclass @dataclass(slots=True) class A: def get_data(self): return "a calculated value" @dataclass(slots=True) class B(A): __slots__ = () # 显式继承父类的槽位 def get_data(self): data = super().get_data() return data + " (modified)" b = B() print(b.get_data()) # a calculated value (modified)
这样无参数super()就能正常工作,因为子类恢复了正常的继承结构,__class__闭包变量可以正确绑定。
内容的提问来源于stack exchange,提问作者enkryptor
相关产品推荐
相关产品推荐

