如何在Python Dataclass中让字典字段实现深拷贝且无需post_init?
Python Dataclass字典字段实现深拷贝(无需post_init)
方案1:利用field的converter参数实现自动深拷贝
Python 3.10+的dataclasses.field提供了converter参数,可以在字段赋值前自动对传入的参数进行转换,刚好适合用来做深拷贝,完全不需要依赖__post_init__。
代码示例:
from dataclasses import dataclass, field from typing import Dict import copy @dataclass class ClassWithDict: the_dict: Dict = field( default_factory=dict, kw_only=True, converter=copy.deepcopy ) toto = {"toto": "tata"} the_class = ClassWithDict(the_dict=toto) assert toto == the_class.the_dict assert toto is not the_class.the_dict # 现在结果为TRUE # 验证深拷贝效果:修改原字典不会影响类内的字典 toto["extra"] = "value" assert the_class.the_dict.get("extra") is None # 断言成立
方案2:自定义默认工厂+转换器(覆盖默认值与传入值场景)
如果需要确保默认空字典和传入外部字典都能保持独立的深拷贝(比如默认值是非空字典时),可以结合default_factory和converter:
from dataclasses import dataclass, field from typing import Dict import copy @dataclass class ClassWithDict: the_dict: Dict = field( default_factory=lambda: copy.deepcopy({"default": "val"}), kw_only=True, converter=copy.deepcopy ) # 测试默认值独立性 inst1 = ClassWithDict() inst1.the_dict["default"] = "modified" inst2 = ClassWithDict() assert inst2.the_dict["default"] == "val" # 两个实例的默认字典相互独立 # 测试传入值深拷贝 external_dict = {"external": "data"} inst3 = ClassWithDict(the_dict=external_dict) external_dict["external"] = "changed" assert inst3.the_dict["external"] == "data" # 深拷贝生效,不受原字典修改影响
版本兼容提示
如果使用的是Python 3.9及以下版本,converter参数尚未支持,可以自定义描述符类来实现类似逻辑:
from dataclasses import dataclass, field from typing import Dict import copy class DeepCopyDict: def __set_name__(self, owner, name): self.name = name def __get__(self, instance, owner): return instance.__dict__.get(self.name, {}) def __set__(self, instance, value): instance.__dict__[self.name] = copy.deepcopy(value) @dataclass class ClassWithDict: the_dict: Dict = field(default_factory=dict, kw_only=True) # 替换字段类型为自定义描述符 the_dict: Dict = DeepCopyDict() toto = {"toto": "tata"} the_class = ClassWithDict(the_dict=toto) assert toto is not the_class.the_dict # 结果为TRUE
内容的提问来源于stack exchange,提问作者Milan
相关产品推荐
相关产品推荐

