更改要迭代的对象绝不是一个好主意。通常
dict,尝试时甚至会引发异常:
name_dict = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6}for k, v in name_dict.items(): name_dict.pop(k)RuntimeError:词典在迭代过程中更改了大小
但是,在您的情况下,您为每个删除的项目添加一个项目。这使它更加混乱。要了解正在发生的事情,您需要知道字典有点像稀疏表。例如,
{1: 1, 3: 3, 5:5}像这样的字典可能看起来像这样(在Python 3.6中已更改,对于3.6及更高版本,以下内容不再正确):hash key value - - - 1 1 1 - - - 3 3 3 - - - 5 5 5 - - - - - - - - -
这也是迭代的顺序。因此,在第一次迭代中,它将转到第二项(
1: 1存储的项)。假设您将密钥更改为,
2然后删除
1该字典,则该密钥将如下所示:
hash key value - - - - - - 2 2 1 3 3 3 - - - 5 5 5 - - - - - - - - -
但是我们仍处于第二行,因此,下一次迭代将转到下一个“非空”条目
2: 1。汤…
使用字符串作为键会更加复杂,因为字符串哈希是随机的(基于每个会话),因此字典中的顺序是不可预测的。
在3.6中,内部布局有所更改,但此处发生了类似的事情。
假设您有以下循环:
name_dict = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6}for k, v in name_dict.items(): # print(k, k+6, name_dict.__sizeof__()) name_dict[k+6] = name_dict.pop(k) # print(name_dict)初始布局是这样的:
key value 1 1 2 2 3 3 4 4 5 5 6 1
第一个循环删除,
1但添加
7。由于字典是在3.6中排序的,因此会在以下位置插入占位符
1:
key value - - 2 2 3 3 4 4 5 5 6 1 7 2
直到您替换
4为为止
10。
key value - - - - - - - - 5 5 6 1 7 2 8 3 9 4 10 5
但是当您
5用
11字典替换时,将需要增加其大小。然后发生一些特殊的情况:占位符被删除:
key value 6 6 7 1 8 2 9 3 10 4 11 5
因此,我们在上一次迭代中位于位置5,现在我们更改了第6行。但是第6行
11: 5现在包含了。哎呀
永远不要更改要迭代的对象:不要在迭代过程中弄乱键(值可以)!
您可以改为保留一个“翻译表”(不知道是否违反了“不创建新字典”的要求,但需要某种存储方式以使您的代码正常工作)并在循环后进行重命名:
translate = {}for k, v in name_dict.items(): print("This is the key: '%s' and this is the value '%s'n" % (k, v) ) new_key = input("Please enter a new key: ") translate[k] = new_key time.sleep(4)for old, new in translate.items(): name_dict[new] = name_dict.pop(old)


