重新初始化dataclass对象时嵌套dataclass未重置的问题
嵌套Dataclass初始化时保留旧值的问题解决
问题重现
你定义了如下嵌套的dataclass:
from dataclasses import dataclass, field from typing import Dict @dataclass class MyNestedClass(): field1: str = "" field2: int = 0 field3: Dict[str, float] = field(default_factory=dict) @dataclass class MyClass(): field1: str = "" field2: int = 0 field3: Dict[str, float] = field(default_factory=dict) field4: MyNestedClass = MyNestedClass()
执行测试代码时发现,每次重新初始化MyClass,field4会保留之前修改的内容:
my_obj = MyClass() print(my_obj) my_obj.field2 = 1 my_obj.field3 = {'something': 2.5} my_obj.field4.field1 = "B" my_obj.field4.field2 = 2 my_obj.field4.field3 = {'something else': 3.14} print(my_obj) my_obj = MyClass() print(my_obj)
输出结果:
MyClass(field1='', field2=0, field3={}, field4=MyNestedClass(field1='', field2=0, field3={})) MyClass(field1='', field2=1, field3={'something': 2.5}, field4=MyNestedClass(field1='B', field2=2, field3={'something else': 3.14})) MyClass(field1='', field2=0, field3={}, field4=MyNestedClass(field1='B', field2=2, field3={'something else': 3.14}))
原因分析
这是Python默认参数绑定机制导致的:
- 当你在
MyClass中定义field4: MyNestedClass = MyNestedClass()时,MyNestedClass()会在定义MyClass的时刻执行,只会创建一个实例。 - 所有后续初始化的
MyClass对象都会共享这个唯一的MyNestedClass实例,修改它的属性后,新创建的MyClass对象自然会复用这个已经被修改的实例。 - 你对
field3使用field(default_factory=dict)是正确的,因为default_factory会在每次初始化MyClass对象时调用传入的函数,生成新的字典实例,避免了共享问题。
正确的初始化方式
把field4的默认值改为使用field(default_factory=MyNestedClass),这样每次初始化MyClass时都会创建新的MyNestedClass实例:
from dataclasses import dataclass, field from typing import Dict @dataclass class MyNestedClass(): field1: str = "" field2: int = 0 field3: Dict[str, float] = field(default_factory=dict) @dataclass class MyClass(): field1: str = "" field2: int = 0 field3: Dict[str, float] = field(default_factory=dict) field4: MyNestedClass = field(default_factory=MyNestedClass)
再次运行测试代码,输出会恢复预期:
MyClass(field1='', field2=0, field3={}, field4=MyNestedClass(field1='', field2=0, field3={})) MyClass(field1='', field2=1, field3={'something': 2.5}, field4=MyNestedClass(field1='B', field2=2, field3={'something else': 3.14})) MyClass(field1='', field2=0, field3={}, field4=MyNestedClass(field1='', field2=0, field3={}))
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

