直接遍历时用 del 会触发 RuntimeError,因字典动态哈希表特性导致迭代器失效;应先收集待删键再统一删除,或用字典推导式重建。
del 会触发 RuntimeError
Python 字典是动态哈希表,遍历过程中修改其大小(比如删键)会导致内部迭代器失效。一旦执行类似 for k in d: del d[k],立刻抛出 RuntimeError: dictionary changed size during iteration。这不是偶然 bug,而是明确的运行时保护机制。
常见误操作包括:在 for k, v in d.items() 循环里调用 del d[k],或用 pop(k) 改变字典结构的同时继续迭代。
最安全、最易读的方式是分两步:先遍历获取待删除键的列表,再对这些键执行删除。这样遍历和修改完全分离,无任何冲突。
list(d.keys()) 后再循环删——虽然能跑通,但它是冗余拷贝,不如直接用 list(d)(字典本身可直接转为键列表)示例:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
keys_to_remove = [k for k in d if k in ['b', 'd']] # 条件判断
for k in keys_to_remove:
del d[k]
# d 变为 {'a': 1, 'c': 3}
如果你本质是要保留满足某条件的键值对,而不是「删不满足的」,那直接重建字典比删旧字典更自然、更函数式。
示例:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
d = {k: v for k, v in d.items() if k not in ['b', 'd']}
# d 变为 {'a': 
1, 'c': 3}
popitem(),但别乱用popitem() 在 Python 3.7+ 是 LIFO(删最后插入的),它本身是原子操作,不会导致迭代错误。但它的行为和「按条件删指定键」完全无关,仅适合清空或实现栈式字典。
while d: d.popitem() 可行,但远不如 d.clear() 直观高效popitem() 能安全配合 for 循环 —— 实际上只要循环体里改了字典大小,依然会崩真正安全的批量删,只取决于「遍历和修改是否分离」,而不是用了哪个删除函数。