为何Python NamedTuple实例会共享可变默认值?
为什么Python NamedTuple实例会共享可变默认值?
from typing import NamedTuple, List, Set, Tuple, Dict class EmbeddingInfoStruct(NamedTuple): emb_names : list[str] =[] idx_in_data: list[int] =[] emb_dim: list[int] =[] info1 =EmbeddingInfoStruct() info1.emb_names.append("name1") info2=EmbeddingInfoStruct() print("info1 address = ", id(info1), ", info2 address = " ,id(info2)) print (info1) print (info2)
运行后输出:
info1 address = 2547212397920 , info2 address = 2547211152576 EmbeddingInfoStruct(emb_names=['name1'], idx_in_data=[], emb_dim=[]) EmbeddingInfoStruct(emb_names=['name1'], idx_in_data=[], emb_dim=[])
这段代码中,info1和info2是内存地址完全不同的两个NamedTuple实例,但修改info1的emb_names后,info2的emb_names也同步变成了['name1'],而非预期的空列表。这看起来像是NamedTuple的字段变成了类的静态属性,原因如下:
这是Python中可变默认参数的经典陷阱,和NamedTuple本身无关,所有使用可变对象作为默认值的场景都会遇到这个问题:
- 当你在类定义中给NamedTuple字段指定可变默认值(比如空列表
[])时,这个默认值是在类定义阶段创建的,属于类的共享属性,而非每个实例独立拥有。 - 所有未显式指定该字段值的实例,都会引用同一个可变对象。修改info1的
emb_names时,本质是在修改这个类级别的共享列表,info2自然也会看到变化。
解决方案
不要直接用可变对象作为默认值,而是使用field(default_factory=...)为每个实例生成独立的可变对象:
from typing import NamedTuple, List from dataclasses import field class EmbeddingInfoStruct(NamedTuple): emb_names: List[str] = field(default_factory=list) idx_in_data: List[int] = field(default_factory=list) emb_dim: List[int] = field(default_factory=list) info1 = EmbeddingInfoStruct() info1.emb_names.append("name1") info2 = EmbeddingInfoStruct() print(info1) # 输出: EmbeddingInfoStruct(emb_names=['name1'], idx_in_data=[], emb_dim=[]) print(info2) # 输出: EmbeddingInfoStruct(emb_names=[], idx_in_data=[], emb_dim=[])
default_factory会在每个实例创建时调用指定函数(比如list()),生成全新的可变对象,确保各个实例的字段互相独立。
内容的提问来源于stack exchange,提问作者imachabeli
相关产品推荐
相关产品推荐

