为何给Enum实例化的冻结数据类添加字符串字段会触发AttributeError?
冻结数据类结合Enum时添加字符串字段触发AttributeError的原因
问题背景
原本将冻结数据类Strand与Enum结合可正常实例化对象,但添加name: str字段后触发AttributeError: can't set attribute,添加tuple或int类型字段则无此问题。
原可运行代码
import enum import dataclasses as dc class Stats(int, enum.Enum): HP = 0 STA = 1 SPD = 2 ATK = 3 DEF = 4 SPATK = 5 SPDEF = 6 @dc.dataclass(frozen=True) class Strand: keeps: tuple[Stats, ...] costs: int class Strands(Strand, enum.Enum): VIT = ((Stats.HP,), 1000) END = ((Stats.STA,), 1000) LTH = ((Stats.SPD,), 1000) AGG = ((Stats.ATK,), 1000) HRD = ((Stats.DEF,), 1000) GFT = ((Stats.SPATK,), 1000) DOM = ((Stats.SPDEF,), 1000) VIGOR = ((Stats.HP, Stats.STA), 5000) MIGHT = ((Stats.ATK, Stats.SPATK), 5000) IMMUN = ((Stats.DEF, Stats.SPDEF), 5000)
修改后报错代码
@dc.dataclass(frozen=True) class Strand: keeps: tuple[Stats, ...] costs: int name: str class Strands(Strand, enum.Enum): VIT = ((Stats.HP,), 1000, "Vitality") END = ((Stats.STA,), 1000, "Endurance") LTH = ((Stats.SPD,), 1000, "Lithe") AGG = ((Stats.ATK,), 1000, "Aggressive") HRD = ((Stats.DEF,), 1000, "Hardening") GFT = ((Stats.SPATK,), 1000, "Gifted") DOM = ((Stats.SPDEF,), 1000, "Dominant") VIGOR = ((Stats.HP, Stats.STA), 5000, "Vigor") MIGHT = ((Stats.ATK, Stats.SPATK), 5000, "Mighty") IMMUN = ((Stats.DEF, Stats.SPDEF), 5000, "Immunity")
报错信息
Traceback (most recent call last): File "test.py", line 20, in <module> class Strands(Strand, enum.Enum): File "C:\Program Files\Python310\lib\enum.py", line 298, in __new__ File "<string>", line 5, in __init__ File "C:\Program Files\Python310\lib\types.py", line 187, in __set__ raise AttributeError("can't set attribute") AttributeError: can't set attribute
原因分析
核心原因是Enum元类会自动为枚举成员设置name属性,而冻结数据类恰好定义了同名的name字段,两者冲突触发报错:
- 创建
Strands枚举类时,Enum元类会逐个处理成员,先调用Strand构造函数创建冻结数据类实例,此时name字段已被初始化并标记为只读(冻结数据类特性)。 - 随后Enum元类尝试给实例设置自己的
name属性(对应枚举成员的标识名,比如"VIT"),但该属性已被冻结数据类设为只读,无法重赋值,因此抛出AttributeError。
之前的tuple或int字段无问题,是因为它们的字段名与Enum内部自动设置的属性(name、value等)不重名,不会触发冲突。
内容的提问来源于stack exchange,提问作者lapraswastaken
相关产品推荐
相关产品推荐

