Rob*_*ert 12 python dictionary for-loop python-3.x
我想帮助理解为什么这段代码没有按预期工作.
如果想要更改字典的键但保留值,他/她可能会使用:
d[new_key] = d.pop[old_key]
Run Code Online (Sandbox Code Playgroud)
我想修改所有键(并保持值到位),但下面的代码跳过某些行 - ("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)
Run Code Online (Sandbox Code Playgroud)
MSe*_*ert 14
改变你正在迭代的对象永远不是一个好主意.通常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)
Run Code Online (Sandbox Code Playgroud)
RuntimeError:字典在迭代期间改变了大小
但是在您的情况下,您为每个删除的项目添加一个项目.这使它更加卷入.要了解发生了什么,您需要知道字典有点像稀疏表.例如,类似的字典{1: 1, 3: 3, 5: 5}可能看起来像这样(这在Python 3.6中已经改变,对于3.6以及更新的以下内容不再正确):
hash key value
- - -
1 1 1
- - -
3 3 3
- - -
5 5 5
- - -
- - -
- - -
Run Code Online (Sandbox Code Playgroud)
这也是迭代的顺序.因此,在第一次迭代中,它将转到第二个项目(1: 1存储的位置).让我们假设您将密钥更改为2并删除1dict看起来像这样的密钥:
hash key value
- - -
- - -
2 2 1
3 3 3
- - -
5 5 5
- - -
- - -
- - -
Run Code Online (Sandbox Code Playgroud)
但是我们仍然在第二行,所以下一次迭代它将进入下一个"非空"条目2: 1.Oups ......
字符串作为键更复杂,因为字符串哈希是随机的(基于每个会话),因此字典内的顺序是不可预测的.
在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)
Run Code Online (Sandbox Code Playgroud)
初始布局是这样的:
key value
1 1
2 2
3 3
4 4
5 5
6 1
Run Code Online (Sandbox Code Playgroud)
第一个循环删除1但添加7.因为字典是在3.6中排序的,所以插入一个占位符1:
key value
- -
2 2
3 3
4 4
5 5
6 1
7 2
Run Code Online (Sandbox Code Playgroud)
这一直持续到你4用10.替换.
key value
- -
- -
- -
- -
5 5
6 1
7 2
8 3
9 4
10 5
Run Code Online (Sandbox Code Playgroud)
但是当你5用11字典替换时需要增加它的大小.然后发生一些特殊情况:删除占位符:
key value
6 6
7 1
8 2
9 3
10 4
11 5
Run Code Online (Sandbox Code Playgroud)
所以,我们在最后一次迭代中处于第5位,现在我们改变了第6行.但是第6行11: 5现在包含了.Oups ...
你可以保留一个"转换表"(不知道是否违反了你的"没有创建新的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)
Run Code Online (Sandbox Code Playgroud)
在 python3 中 dict.items() 只是 dict 上的一个视图。因为在迭代时不允许修改可迭代对象,所以在迭代 dict.items() 时不允许修改 dict。您必须在迭代之前将 items() 复制到列表
for k, v in list(name_dict.items()):
...
name_dict[new_key] = name_dict.pop(k)
Run Code Online (Sandbox Code Playgroud)
这确实满足了您的“无新字典”要求,尽管该列表实际上包含您所有数据的完整副本。
您可以通过仅复制键来稍微放松内存占用
for k in list(name_dict):
v = name_dict.pop(k)
...
name_dict[new_key] = v
Run Code Online (Sandbox Code Playgroud)
编辑:感谢 Sven Krüger,他提出了旧键-新键冲突问题的可能性。在这种情况下,你必须去
kv = list(name_dict.items())
name_dict.clear()
for k, v in kv :
...
name_dict[new_key] = v
Run Code Online (Sandbox Code Playgroud)
顺便说一句,有一个不创建新字典的用例,当前的字典可能会在其他地方被引用。
| 归档时间: |
|
| 查看次数: |
12447 次 |
| 最近记录: |