Python字典异常行为:不同版本循环修改字典的输出差异原因
为什么Python 2.7和3.6执行这段代码的输出不同?
这个问题的核心在于Python不同版本中字典的内部实现和迭代器逻辑的差异,咱们分版本拆解:
Python 2.7的行为原因
- Python2.7的字典底层是传统哈希表结构,迭代器会直接遍历哈希表的所有槽位(bucket)。初始创建
{0: None}时,字典的默认哈希表大小是8(共8个槽位)。 - 循环中每次执行
del d[i]删除当前键,再d[i+1] = None添加新键:因为整数的哈希值等于自身,新键i+1会刚好落在哈希表的第i+1个槽位。 - 迭代器会逐个检查每个槽位,只要槽位里有键就会处理它。由于每次处理后新键都落在下一个未被检查的槽位,迭代器会一直遍历完所有8个槽位,直到槽位7处理完成后,没有更多槽位可遍历,循环结束。所以输出是
0 1 2 3 4 5 6 7。
Python 3.6的行为原因
- Python3.6对字典做了重大重构:
- 采用了紧凑数组+哈希表的新结构,不仅能保存插入顺序,迭代器也改为基于记录键插入顺序的数组来遍历,而非直接遍历哈希表槽位。
- 引入了版本号校验机制:每次修改字典(添加/删除键)都会增加字典的内部版本号,迭代器会在每次迭代时校验版本号。如果发现版本号和迭代开始时不一致,会触发
RuntimeError终止迭代——但这里有个特殊情况:当删除的是当前正在迭代的键时,迭代器会允许这次修改,但新添加的键不会被纳入当前的迭代序列。
- 实际运行中,由于新结构的特性,这种循环不会无限执行,而是在有限几次迭代后终止(你看到的输出到4就是这个原因),本质上是因为迭代器不会去遍历迭代开始后新添加的键,每次删除当前键后,迭代器的后续迭代会逐步耗尽初始的迭代状态,最终停止。
内容的提问来源于stack exchange,提问作者user1717828
相关产品推荐
相关产品推荐

