You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python dataclass设置IntEnum默认值时多实例属性同内存地址问题

问题解答

该行为属于Python的预期设计

你观察到的现象和dataclass本身无关,是Python两个核心特性的正常表现:

  • 小整数驻留优化:Python为了降低频繁创建销毁小整数的性能开销,会默认缓存[-5, 256]区间内的所有整数对象,整个进程中所有用到这个区间内整数的地方,都会复用同一个缓存对象,因此默认值0的id在多个实例中完全相同。
  • 枚举成员单例特性:所有继承自Enum的枚举类(包括IntEnum)的成员都是全局单例,同一个枚举值在进程中只会存在一个实例,因此多个实例引用同一个枚举成员时,id必然相同。

需要特别说明的是:int和IntEnum都属于不可变类型,即使多个实例共享同一个对象引用,也完全不会出现你可能担心的"改一个影响所有"的问题。对实例属性的赋值操作只会修改当前实例属性的指向,不会修改原对象内容,也不会联动影响其他实例的属性值,因此这个现象本身不会带来任何业务问题,你目前的额外赋值操作完全没有必要。

修改赋值后id不同的原因

你修改属性值后id变化,只是因为属性指向了新的对象:

  • 如果你给两个实例的a属性都赋值为同一个小整数(比如10),你会发现两者的id会再次变为相同
  • 如果你给两个实例的b属性都赋值为同一个枚举成员(比如E_Enum.First),两者的id也会再次相同

初始化阶段强制属性地址唯一的方法(不推荐,无实际价值)

如果你确实需要在初始化阶段就保证属性指向不同的对象,可以使用dataclass的field的default_factory参数,在每个实例初始化时生成新对象:

from dataclasses import dataclass, field
from enum import IntEnum

class E_Enum(IntEnum):
    Init = 0
    First = 1
    Second = 2

@dataclass
class A():
    # 每次初始化生成新的int对象,绕过小整数缓存
    a: int = field(default_factory=lambda: int('0'))
    # 注意:枚举成员单例是语言层面强制的,无法生成两个值相同的不同IntEnum实例
    # 如果需要同值不同id的枚举类对象,只能放弃使用IntEnum,自行实现类似功能的普通类
    b: E_Enum = E_Enum.Init

注意这个操作除了浪费内存之外,不会带来任何实际收益,生产环境不建议这么做。

内容的提问来源于stack exchange,提问作者flok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 16:06:03