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)
。
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)
。
不,这不是一个错误。这其实是explicitly documented:
键和值指的是这个非随机的,不同的Python实现不同而不同,取决于插入和删除的字典的历史以任意顺序遍历。如果按键,值和项目视图被重复执行而不对词典进行中间修改,则项目顺序将直接对应。而添加或删除字典中的条目可能引发
RuntimeError
或无法遍历所有条目[...]
迭代意见。
大胆强调我的。
您正在遍历键,同时添加和删除词典中的条目。这工作了几次迭代,然后你击中了一个未能遍历所有条目案件和迭代停止。
会发生什么情况是您在6次添加时触发重新大小,并导致迭代在此时失败; “下一个”键现在插入“更早”的插槽中。发生这种情况的都测试,你只是不知道它在这两种情况下迭代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
它运行,因为当前dict
实现了hash table of size 8开始的5倍,并调整大小触发when the table is 2/3s full (您最初的dict有1项,5个插入使其> (8 * 2/3 == 5.333333)
该表是越来越充满DKIX_DUMMY
entities,进入时,删除键(正确处理散列冲突需要)。
注意,这是所有高度依赖于实现的。在Python 3.5和之前的版本中,这两个代码片段只是迭代而已一次(即使使用for k in d:
来避免为键创建列表对象);迭代在3.6中继续,因为实现发生了变化,现在迭代遵循插入顺序。未来的Python版本可以自由地再次改变实现。
为什么会是一个错误?您在迭代*时删除并添加键*。你很幸运,你并没有陷入无限循环。 –
绝不*改变*集合,而*重复*。特别是不是词典,因为它会导致怪异的行为。 –
@ user2725109:你怎么知道第一个循环只运行一次?对于所有你知道它跑了1000次。 –