循环中更新Python字典出现异常结果的原因解析
为何循环更新字典会导致列表中已添加的字典也被修改?
我尝试遍历一个值列表,构造字典以结构化方式保存每个值,再将该字典添加到结果列表中,却遇到了异常行为。
示例代码如下:
values_list = [1,2,3] # Basic dict result_dict = { 'my_value': '' } # Iterate, craft a dictionary, and append result dicts_list = [] for value in values_list: result_dict.update({'my_value': value}) dicts_list.append(result_dict) print(dicts_list)
我先创建一个基础字典,接着遍历值列表并更新该字典,最后将构造好的字典添加到结果列表dicts_list中。
预期结果:
[{'my_value': 1}, {'my_value': 2}, {'my_value': 3}]
实际得到的结果:
[{'my_value': 3}, {'my_value': 3}, {'my_value': 3}]
看起来每次循环不仅会更新基础字典(这是预期的),还会更新之前循环中已添加到结果列表的字典。
我通过将基础字典的定义嵌套在for循环内解决了该问题:
values_list = [1,2,3] # Iterate, craft a dictionary, and append result dicts_list = [] for value in values_list: result_dict = {'my_value': ''} result_dict.update({'my_value': value}) dicts_list.append(result_dict) print(dicts_list)
想请教:第一种方法存在什么问题?为何循环会导致已添加到列表中的字典被更新?
问题根源:Python可变对象的引用特性
在Python里,字典是可变对象,当你把一个字典添加到列表中时,列表存储的并不是这个字典的副本,而是指向该字典对象的引用。
第一种方法里,你在循环外只创建了一个result_dict字典对象。每次循环执行result_dict.update(...)时,都是在修改同一个字典对象的内容;而dicts_list.append(result_dict)只是把这个字典的引用重复添加到列表里。所以最终列表里的三个元素其实都指向同一个字典对象,当最后一次循环把字典的值改成3后,所有引用指向的都是这个最终状态的字典,打印出来自然全是3。
而你后来的解决方法,把result_dict = {'my_value': ''}放到循环内部,意味着每次循环都会创建一个全新的字典对象。每次更新的都是不同的字典,添加到列表里的也是不同对象的引用,所以每个元素都是独立的,最终结果符合预期。
额外优化方案
除了把字典定义放循环里,你还可以用更简洁的方式实现需求:
方法1:直接在循环中创建新字典
values_list = [1,2,3] dicts_list = [] for value in values_list: dicts_list.append({'my_value': value})
方法2:使用copy()生成字典副本
values_list = [1,2,3] result_dict = {'my_value': ''} dicts_list = [] for value in values_list: result_dict['my_value'] = value dicts_list.append(result_dict.copy()) # 添加副本而非原对象引用
内容的提问来源于stack exchange,提问作者Franz
相关产品推荐
相关产品推荐

