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

为何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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 23:31:22