我想要一些帮助来理解为什么这段代码不能像预期的那样工作.

如果想要更改字典的键但保留值,他/她可以使用:

d[new_key] = d.pop[old_key]

我想修改所有键(并保持值不变),但下面的代码跳过了某些行("col2")保持不变.是不是因为字典是无序的,而我一直在更改字典中的值?

在不创建新字典的情况下,如何更改键并保留值?

import time
import pprint

name_dict = {"col1": 973, "col2": "1452 29th Street",
             "col3": "Here is a value", "col4" : "Here is another value",
             "col5" : "NULL", "col6": "Scottsdale",
             "col7": "N/A", "col8" : "41.5946922",
             "col9": "Building", "col10" : "Commercial"}


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: ")
    name_dict[new_key] = name_dict.pop(k)
    time.sleep(4)

pprint.pprint(name_dict)

推荐答案

更改正在迭代的对象从来都不是一个好主意.通常情况下,dict甚至会在try 时引发异常:

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,dict将如下所示:

hash    key    value
   -      -        - 
   -      -        - 
   2      2        1
   3      3        3
   -      -        - 
   5      5        5
   -      -        - 
   -      -        - 
   -      -        - 

但我们仍然在第二行,所以下一次迭代将转到下一个"notempty"条目,即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

这一直持续到你用10代替4.

key   value
  -       -
  -       -
  -       -
  -       -
  5       5
  6       1
  7       2
  8       3
  9       4
 10       5

但是当你用11替换5时,字典需要增加它的大小.然后发生了一些特殊的事情:占位符被删除:

key   value
  6       6
  7       1
  8       2
  9       3
 10       4
 11       5

所以,我们在上一次迭代中处于第5位,现在我们更改第6行.但是6号线现在有11: 5个.呃...

永远不要改变你正在迭代的对象:不要在迭代过程中弄乱键(值是可以的)!

你可以保留一个"翻译表"(不知道这是否违反了你的"不创建新的dict"要求,但你需要某种存储来让代码正常工作),并在循环后进行重命名:

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)

Python-3.x相关问答推荐

如果行在所有上级索引中都为0,如何删除下级索引行?

如何计算累积几何平均数?

类变量的Python子类被视为类方法

Pandas教程:如何更新行内数值的位置

「Python Pandas」多级索引列和行匹配,如果列和行名称相似,则排除这些单元格中的值添加

如何查找以开头并替换的字符串

如何在 histplot 中标记核密度估计

将两列合并为一列,将它们制成字典 - pandas - groupby

matplotlib.pyplot 多边形,具有相同的纵横比和紧凑的布局

Python 3 `str.__getitem__` 的计算复杂度是多少?

Pandas 值列中列表中元素的计数

没有可重定向到的 URL.提供一个 url 或在模型上定义一个 get_absolute_url 方法

如何从脚本中提取 PDF 文档的标题以进行重命名?

在带有 M1 芯片(基于 ARM 的 Apple Silicon)的 Mac 上安装较早版本的 Python(3.8 之前)失败

pysftp vs. Paramiko

从大字典中弹出 N 项的最快方法

在没有时间的python中创建日期

matplotlib - 模块sip没有属性setapi

字典理解中的操作顺序

如何从集合中删除多个元素?