for循环填充字典时所有键值被覆盖,错误原因及解决方法
问题描述
我有一个转置后的Dataframe tr:
| 7128 | 8719 | 14051 | 14636 | |
|---|---|---|---|---|
| JDUTC_0 | 2451957.36 | 2452149.36 | 2457243.98 | 2452531.89 |
| JDUTC_1 | 2451957.37 | 2452149.36 | 2457243.99 | 2452531.90 |
| JDUTC_2 | 2451957.37 | 2452149.36 | 2457244.00 | 2452531.91 |
| JDUTC_3 | NaN | 2452149.36 | NaN | NaN |
| JDUTC_4 | NaN | 2452149.36 | NaN | NaN |
| JDUTC_5 | NaN | 2452149.36 | NaN | NaN |
| JDUTC_6 | 1.23 | 2452149.37 | NaN | NaN |
| JDUTC_7 | NaN | NaN | NaN | NaN |
| JDUTC_8 | NaN | NaN | NaN | NaN |
| JDUTC_9 | NaN | NaN | NaN | NaN |
我通过以下代码创建字典a:
a = {} b=[] for _, contents in tr.items(): b.clear() for ind, val in enumerate(contents): if np.isnan(val): b.append(ind) continue else: pass print(_) print(b) a[_] = b print(a)
运行后得到如下输出:
7128 [3, 4, 5, 7, 8, 9] {7128: [3, 4, 5, 7, 8, 9]} 8719 [7, 8, 9] {7128: [7, 8, 9], 8719: [7, 8, 9]} 14051 [3, 4, 5, 6, 7, 8, 9] {7128: [3, 4, 5, 6, 7, 8, 9], 8719: [3, 4, 5, 6, 7, 8, 9], 14051: [3, 4, 5, 6, 7, 8, 9]} 14636 [3, 4, 5, 6, 7, 8, 9] {7128: [3, 4, 5, 6, 7, 8, 9], 8719: [3, 4, 5, 6, 7, 8, 9], 14051: [3, 4, 5, 6, 7, 8, 9], 14636: [3, 4, 5, 6, 7, 8, 9]}
我预期字典a的结构为:
{7128: [3, 4, 5, 7, 8, 9], 8719: [7, 8, 9], 14051: [3, 4, 5, 6, 7, 8, 9], 14636: [3, 4, 5, 6, 7, 8, 9]}
请问我哪里出错了?为什么a[_] = b会覆盖之前所有键的值,而print(_)已经验证_始终是下一个列标签?
问题原因与解决方法
错误原因
核心问题是列表的引用传递特性:
- 你只创建了一个全局列表
b,每次循环用b.clear()清空后重新添加元素,本质上始终在操作同一个列表对象。 - 字典
a中所有键存储的都是这个列表b的引用,而非独立的副本。所以每次修改b的内容,字典里所有已存入的列表都会同步变化,最终所有键的值都会变成最后一次循环中b的内容。
修正方法
不要复用同一个列表,每次循环创建新的列表对象即可:
a = {} for _, contents in tr.items(): b = [] # 每次循环新建列表,替代复用旧列表 for ind, val in enumerate(contents): if np.isnan(val): b.append(ind) print(_) print(b) a[_] = b print(a)
或者用更简洁的列表推导式写法:
import numpy as np a = {col: [i for i, val in enumerate(tr[col]) if np.isnan(val)] for col in tr.columns}
这样每个字典键都会对应独立的列表,不会出现值被覆盖的问题。
内容的提问来源于stack exchange,提问作者Jonathan Sullivan
相关产品推荐
相关产品推荐

