迭代时修改字典。 Python dict中的错误?

时间:2017-06-26 15:59:27

标签: python python-3.x dictionary for-loop python-internals

的输出
d = {1: 1}
for k in d.keys():
    d['{}'.format(k)] = d.pop(k)
print(d)

{'1': 1}

的输出
d = {1: 1}
for k in d.keys():
    d['i{}'.format(k)] = d.pop(k)
print(d)

{'iiiii1': 1}。这是一个错误吗?我正在运行Python 3.6.1 :: Anaconda 4.4.0 (x86_64)

1 个答案:

答案 0 :(得分:18)

不,这不是错误。事实上这是explicitly documented

  

键和值以任意顺序迭代,这是非随机的,在Python实现中各不相同,并且取决于字典的插入和删除历史。如果迭代了键,值和项视图而没有对字典进行干预修改,则项的顺序将直接对应。

     

[...]

     

在字典中添加或删除条目时迭代视图可能会引发Integer或无法迭代所有条目。

大胆强调我的。

您正在迭代密钥,同时在字典中添加和删除条目。这工作了几次迭代,然后你点击无法迭代所有条目案例并且迭代停止。

在6次添加时会触发重新调整大小,这会导致迭代失败; ' next'密钥现在已经在之前的'插槽。对于两个测试都会发生这种情况,在这两种情况下你都没有意识到它会迭代5次:

RuntimeError

它运行了5次,因为当前的>>> d = {1: 1} >>> for i, k in enumerate(d): ... print(i) ... d['{}'.format(k)] = d.pop(k) ... 0 1 2 3 4 >>> d = {1: 1} >>> for i, k in enumerate(d): ... print(i) ... d['i{}'.format(k)] = d.pop(k) ... 0 1 2 3 4 实现以hash table of size 8开头,并且触发了调整大小when the table is 2/3s full(您的初始dict有1个条目,5个插入使其成为{{ 1}}。当你删除一个密钥(需要正确处理哈希冲突)时,表格会被DKIX_DUMMY entities填充。

请注意,这些都是高度依赖于实现的。在Python 3.5及之前,两个片段只迭代一次(即使您使用dict来避免为键创建列表对象);迭代在3.6中继续,因为实现已更改,迭代现在遵循插入顺序。未来的Python版本可以自由地再次改变实现。