Python中如何避免dataclass成员被默认作为类变量实例化?
Python dataclass实例属性共享问题排查与解决
问题根因
你遇到的属性共享问题是dataclass字段规则和Python类可变默认值特性共同导致的,核心原因有两点:
- 字段识别规则限制:dataclass仅会将带有PEP 526标准类型注解的类属性识别为需要单独实例化的实例字段。未加类型注解的属性会被直接作为类属性处理,所有实例共享同一份内存对象。
- 可变默认值初始化陷阱:类定义阶段设置的可变类型默认值(自定义类实例、列表、numpy数组等),只会在类加载时生成一次,所有未传对应参数的实例都会默认引用这同一个对象。
dataclass()实际会检查字段类型的两处场景之一,就是判断字段是否为PEP 526定义的类变量,判定逻辑为检查字段类型是否为typing.ClassVar。若字段属于ClassVar类型,就不会被纳入dataclass字段范围,会被dataclass机制忽略,这类ClassVar伪字段也不会被模块级的fields()函数返回。
现象对应解释
你给出的运行结果完全符合上述规则:
- 未加类型注解的
alpha属于类属性,因此所有实例的alpha指向同一块内存地址 color字段虽然加了类型注解,但默认值是类加载时生成的单个Color实例,所有未传color参数的实例都共享这个对象- 修改
x.color.r是修改共享对象的属性,因此y的color属性同步变更;给x.number赋值是在x实例上新增了实例属性覆盖了类属性,因此y的number不受影响,和打印的__dict__结果完全匹配。
修复方案
使用dataclasses.field的default_factory参数为可变类型字段生成每个实例独立的默认值,同时为所有字段补全类型注解,修改后的代码如下:
from dataclasses import dataclass, field import numpy as np @dataclass class Color: r: int = 0 g: int = 0 b: int = 0 @dataclass class NumberColor: color: Color = field(default_factory=Color) number: int = 0 alpha: np.ndarray = field(default_factory=lambda: np.zeros(3))
修改后每个实例的color、alpha都会在初始化时生成独立的新对象,修改单个实例的属性不会影响其他实例。
内容的提问来源于stack exchange,提问作者Mayank
相关产品推荐
相关产品推荐

