Python循环中字典列表输出异常原因解析
问题原因分析:字典引用导致的列表元素异常修改
问题场景
你期望生成包含所有参数组合的字典列表,正确输出应该是:
[ {'l1': 0, 'lp1': 0}, {'l1': 0, 'lp1': 1}, {'l1': 1, 'lp1': 0}, {'l1': 1, 'lp1': 1} ]
但运行提供的代码后,最终得到的却是所有lp1值都为1的列表:
[ {'l1': 0, 'lp1': 1}, {'l1': 0, 'lp1': 1}, {'l1': 1, 'lp1': 1}, {'l1': 1, 'lp1': 1} ]
且迭代过程中打印的临时结果是正确的,但后续迭代会修改已添加到列表中的元素。
你的代码如下:
from itertools import product from typing import Iterable, Any l_params = { "l1": [0,1] } lp_params = { "lp1": [0,1] } def grid_parameters(parameters: dict[str, Iterable[Any]]) -> Iterable[dict[str, Any]]: for params in product(*parameters.values()): yield dict(zip(parameters.keys(), params)) outlist = [] for l_settings in grid_parameters(l_params): for lp_settings in grid_parameters(lp_params): settings = l_settings settings['lp1'] = lp_settings['lp1'] outlist.append(settings) print('ls', outlist)
核心原因:字典是可变对象,列表存储的是引用
Python中,字典属于可变对象,当你执行settings = l_settings时,并没有创建新的字典,而是让settings指向了和l_settings完全相同的内存地址。
每次循环的具体逻辑:
- 第一次内层循环:给这个共享的字典添加
lp1:0,并把字典的引用加入列表; - 第二次内层循环:修改同一个字典的
lp1值为1,此时列表中之前添加的引用指向的还是这个字典,所以已存在的元素也会跟着变成lp1:1; - 外层循环切换到
l1:1的字典时,重复上述逻辑,最终列表里的所有元素都指向两个原始字典(l1:0和l1:1),而这两个字典的lp1最后都被修改为1,所以最终输出全是lp1:1。
你用字符串解决问题,是因为字符串是不可变对象,每次转换都会生成新的字符串实例,列表里存储的是不同的字符串,不会被后续修改影响。
解决办法:创建字典的副本
要避免这个问题,每次循环时需要创建字典的新副本,而不是直接引用原字典。常用两种方式:
- 使用字典的
copy()方法:
for l_settings in grid_parameters(l_params): for lp_settings in grid_parameters(lp_params): settings = l_settings.copy() # 创建原字典的副本 settings['lp1'] = lp_settings['lp1'] outlist.append(settings)
- 使用字典解包生成新字典:
for l_settings in grid_parameters(l_params): for lp_settings in grid_parameters(lp_params): settings = {**l_settings, **lp_settings} # 合并两个字典生成新实例 outlist.append(settings)
这样每次添加到列表的都是独立的字典实例,后续修改不会影响已添加的元素。
内容的提问来源于stack exchange,提问作者Graham Webber
相关产品推荐
相关产品推荐

