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

为什么Python中[defaultdict(int)] * 3返回三个指向同一对象的引用?

编辑说明

为什么[defaultdict(int)] * 3会返回三个指向同一对象的引用?

原始标题

Python中将defaultdict列表解包到变量时出现不符合预期的行为

问题描述

将初始化好的defaultdict类型列表解包赋值给多个变量时,运行表现与预期不符,使用的Python版本为3.9.1,复现代码如下:

# 两种写法行为一致,运行正常
a,b,c = [int(), int(), int()]
d,e,f = [int()] * 3

# 预期两种写法行为一致,但实际运行表现不同
l,m,p = [defaultdict(int), defaultdict(int), defaultdict(int)]
q,r,s = [defaultdict(int)] * 3

完整运行输出:

>>> a,b,c = [int(), int(), int()]
>>> a+=4; b+=2; c+=7
>>> a,b,c
(4, 2, 7)
>>> d,e,f = [int()] * 3
>>> d+=11; e+=8; f+= 41
>>> d,e,f
(11, 8, 41)

>>> from collections import defaultdict
>>> l,m,p = [defaultdict(int), defaultdict(int), defaultdict(int)]
>>> l['a']+=1; m['b']+=2; m['c']+=3;
>>> l,m,p
(
  defaultdict(<class 'int'>, {'a': 1}), 
  defaultdict(<class 'int'>, {'b': 2, 'c': 3}), 
  defaultdict(<class 'int'>, {})
)
>>> q,r,s = [defaultdict(int)] * 3
>>> q['a']+=111; r['b']+=222; m['c']+=333;
>>> q,r,s
(
  defaultdict(<class 'int'>, {'a': 111, 'b': 222}), 
  defaultdict(<class 'int'>, {'a': 111, 'b': 222}), 
  defaultdict(<class 'int'>, {'a': 111, 'b': 222})
)

问题解答

这个现象是Python的序列乘法规则、可变/不可变对象的差异共同导致的,核心逻辑如下:

  • [x] * N的运行规则:序列乘号操作只会复制对象的引用,不会重新执行x的初始化逻辑。也就是说[defaultdict(int)] * 3只会调用一次defaultdict(int)生成实例,然后把这个实例的引用复制3次放到列表里,三个元素本质指向同一个内存地址的对象。
  • int场景表现正常的原因:int是不可变对象,执行d += 11时并不会修改原有的int实例,而是会生成一个全新的int对象,再把变量d的指针指向这个新对象,不会影响列表里原来的实例,所以三个变量的修改互不干扰。
  • defaultdict表现异常的原因:defaultdict是可变对象,执行q['a'] += 111是直接修改q指向的defaultdict实例本身的内容,没有创建新对象。而q、r、s三个变量都指向同一个defaultdict实例,所以修改任意一个变量的内容,另外两个也会同步变化。

解决方案

如果需要生成多个独立的defaultdict实例,使用列表推导式写法即可:

q, r, s = [defaultdict(int) for _ in range(3)]

列表推导式的每次循环都会重新执行一次defaultdict(int)初始化,生成三个完全独立的实例,修改时不会互相影响。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:18:03