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

列表推导式与乘法生成列表的元素赋值差异及引用共享疑问

为什么列表乘法和列表推导式生成的列表元素赋值行为不同?

先看你给出的代码示例:

nums = [1,1,1,2,2,0,3]

lst1 = [[]] * (len(nums) + 1)
lst2 = [[] for i in range(len(nums) + 1)]

print(lst1)        #[[], [], [], [], [], [], [], []]
print(lst2)        #[[], [], [], [], [], [], [], []]

lst1[3].append(2)  
lst2[3].append(2) 

print(lst1)        #[[2], [2], [2], [2], [2], [2], [2], [2]]
print(lst2)        #[[], [], [], [2], [], [], [], []]

核心原因:引用共享 vs 独立对象创建

你猜的完全正确!lst1 = [[]] * n这种写法并没有创建n个独立的空列表,而是把同一个空列表的引用复制了n次。也就是说,lst1里的每一个元素,实际上都指向内存中同一个列表对象。

当你执行lst1[3].append(2)时,你是在修改这个唯一的列表对象,所以lst1中所有指向它的位置都会同步看到这个变化——就像多个变量指向同一个盒子,你往盒子里放东西,所有能看到这个盒子的地方都会看到里面多了东西。

而列表推导式[[] for i in range(n)]则完全不同:每次循环迭代时,都会执行一次[],也就是创建一个全新的空列表。所以lst2里的每个元素都是独立的列表对象,修改其中一个只会影响对应的位置,其他元素不受任何影响。

这种引用共享机制有什么用途?

虽然这个特性很容易踩坑,但在某些场景下它是实用的:

  • 共享状态维护:如果你需要多个位置共享同一个可变对象的状态,比如多个模块或函数需要操作同一个列表来记录日志,这种写法可以快速创建多个引用指向同一个对象。
  • 内存优化:当你要创建的对象体积很大(比如一个包含大量数据的列表或自定义对象),而你确实不需要多个独立副本时,复用同一个对象的引用可以节省内存空间。
  • 批量绑定回调:在一些GUI编程场景中,可能需要多个控件绑定同一个回调函数对象,类似的引用复用逻辑也适用。

不过要注意,除非你明确需要这种共享行为,否则尽量用列表推导式(或者循环创建独立对象)来避免意外的全局修改问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 18:05:19