Python字典删除列表元素为何影响所有值?如何解决?
问题重现
你创建了这样的字典:
my_dict = { '100':[['a', [10], [5]]], '101':[['a', [10], [7]]], '102':[['a', [10], [11]]], '103':[['a', [10], [4]]], }
创建逻辑是循环id列表,根据条件填充info_list后添加到字典中。当你执行以下代码删除元素10时:
for k in my_dict.keys(): my_dict[k][1].remove(10)
发现删除第一个键'100'对应元素里的10后,所有键的对应值里的10都消失了。
原因分析
问题出在Python中列表是可变对象,你的多个info_list都引用了同一个列表对象。
看你的创建代码:当some_condition满足时,你直接把list1插入到info_list的索引1位置。如果list1是同一个包含[10]的列表实例(比如从其他函数返回的是同一个列表,而非每次生成新列表),那么所有符合条件的info_list的索引1位置,指向的都是内存中的同一个列表对象。
这就好比多个变量都指向同一个盒子,你从这个盒子里拿走东西,所有能看到这个盒子的变量都会发现东西没了。所以你修改其中一个info_list里的列表,其他引用它的地方都会同步变化。
另外补充一点:你的遍历代码还有个小错误——my_dict[k]是一个包含单个元素的列表(比如my_dict['100']是[['a', [10], [5]]]),正确的索引应该是my_dict[k][0][1].remove(10),不过这不是导致所有元素被删除的核心原因。
解决方法
要避免这种问题,关键是每次给info_list添加列表时,创建原列表的副本,而不是直接引用原对象。Python中创建列表副本的方式有几种:
- 使用列表的
copy()方法:list1.copy() - 用
list()构造函数包裹原列表:list(list1) - 使用切片语法:
list1[:]
修改你的创建代码,把插入list1的部分改成副本即可:
if some_condition: info_list.insert(0, 'a') # 创建list1的副本,避免多个info_list引用同一个对象 info_list.insert(1, list1.copy()) else: info_list.insert(0, 'a') info_list.insert(1, [])
这样每个info_list的索引1位置都是独立的列表对象,修改其中一个不会影响其他的。
如果是事后要修复已经创建好的字典,也可以遍历字典,为每个列表创建副本:
for k in my_dict: # 为索引1位置的列表创建副本 my_dict[k][0][1] = my_dict[k][0][1].copy()
之后再执行删除操作就只会影响当前键对应的元素了。
内容的提问来源于stack exchange,提问作者Vishal

