Python中如何创建字段含独立实例的多个dataclass实例?
问题:Dataclass子类实例共享类变量导致字段值一致
编写解析器时,希望将通用逻辑放在父类RecordParser中,但所有子类实例的字段值最终都相同。核心困惑在于dataclass对类变量和实例变量的处理方式,当前在__post_init__中直接操作self.__dict__可能存在问题,需要实现每个实例拥有独立的VarSlice对象实例。
原代码
from dataclasses import dataclass class VarSlice: def __init__(self, start, end): self.slice = slice(start, end) self.value = None @dataclass class RecordParser(): line: str def __post_init__(self): for k, var in self.__dict__.items(): if isinstance(var, VarSlice): self.__dict__[k].value = self.line[var.slice] @dataclass class HeaderRecord(RecordParser): sender : VarSlice = VarSlice(3, 8) k = HeaderRecord(line="abcdefgh") kk = HeaderRecord(line="123456789") print(k.sender.value) print(kk.sender.value)
实际输出
45678 45678
期望输出
abcde 45678
尝试将VarSlice改为dataclass后问题仍存在。
解决方案
问题根源
dataclass中如果直接给字段赋值可变对象(比如VarSlice(3,8))作为默认值,这个对象会成为类级别的共享变量,所有子类实例都会复用同一个对象。因此k和kk的sender指向同一个VarSlice实例,最后一次赋值的value会覆盖之前的结果。
修复步骤
- 使用
dataclasses.field的default_factory参数,为每个实例创建独立的VarSlice对象; - 优化父类
__post_init__的遍历逻辑,改用dataclasses.fields更规范地处理字段。
修改后的完整代码
from dataclasses import dataclass, field class VarSlice: def __init__(self, start, end): self.slice = slice(start, end) self.value = None @dataclass class RecordParser: line: str def __post_init__(self): # 遍历当前类的所有字段,而非直接操作__dict__ from dataclasses import fields for field_info in fields(self): field_value = getattr(self, field_info.name) if isinstance(field_value, VarSlice): field_value.value = self.line[field_value.slice] @dataclass class HeaderRecord(RecordParser): # 使用default_factory为每个实例生成独立的VarSlice sender: VarSlice = field(default_factory=lambda: VarSlice(3, 8)) k = HeaderRecord(line="abcdefgh") kk = HeaderRecord(line="123456789") print(k.sender.value) # 输出: abcde print(kk.sender.value) # 输出: 45678
说明
default_factory接收一个无参函数,每次创建HeaderRecord实例时,都会调用该函数生成新的VarSlice对象,确保每个实例拥有独立的实例;- 改用
fields(self)遍历字段,避免直接操作__dict__可能带来的意外问题,同时更符合dataclass的设计规范。
内容的提问来源于stack exchange,提问作者tenup
相关产品推荐
相关产品推荐

