Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在迭代Python dict时修改它_Python_Dictionary - Fatal编程技术网

在迭代Python dict时修改它

在迭代Python dict时修改它,python,dictionary,Python,Dictionary,假设我们有一个Python字典d,我们像这样对它进行迭代: for k,v in d.iteritems(): del d[f(k)] # remove some item d[g(k)] = v # add a new item (f和g只是一些黑盒变换。) 换句话说,我们尝试在使用iteritems对d进行迭代的同时,向其添加/删除项 这个定义清楚吗?你能提供一些参考资料来支持你的回答吗 (很明显,如果它坏了,如何修复它,所以这不是我想要的角度。)你不能这样做,至少用d.i

假设我们有一个Python字典
d
,我们像这样对它进行迭代:

for k,v in d.iteritems():
    del d[f(k)] # remove some item
    d[g(k)] = v # add a new item
f
g
只是一些黑盒变换。)

换句话说,我们尝试在使用
iteritems
d
进行迭代的同时,向其添加/删除项

这个定义清楚吗?你能提供一些参考资料来支持你的回答吗


(很明显,如果它坏了,如何修复它,所以这不是我想要的角度。)

你不能这样做,至少用
d.iteritems()
。我试过了,但是Python失败了

RuntimeError: dictionary changed size during iteration
如果您改为使用
d.items()
,则它可以工作


在Python3中,
d.items()
是字典中的一个视图,就像Python2中的
d.iteritems()
一样。要在Python3中执行此操作,请使用
d.copy().items()
。类似地,这将允许我们迭代字典的副本,以避免修改我们正在迭代的数据结构。

以下代码表明,这没有得到很好的定义:

def f(x):
    return x

def g(x):
    return x+1

def h(x):
    return x+10

try:
    d = {1:"a", 2:"b", 3:"c"}
    for k, v in d.iteritems():
        del d[f(k)]
        d[g(k)] = v+"x"
    print d
except Exception as e:
    print "Exception:", e

try:
    d = {1:"a", 2:"b", 3:"c"}
    for k, v in d.iteritems():
        del d[f(k)]
        d[h(k)] = v+"x"
    print d
except Exception as e:
    print "Exception:", e
第一个示例调用g(k),并抛出一个异常(字典在迭代过程中更改了大小)

第二个示例调用h(k)并没有抛出异常,但输出:

{21: 'axx', 22: 'bxx', 23: 'cxx'}
从代码上看,这似乎是错误的-我本以为会是这样的:

{11: 'ax', 12: 'bx', 13: 'cx'}

亚历克斯·马泰利也参与其中

在容器上循环时,更换容器(如dict)可能不安全。 因此
deld[f(k)]
可能不安全。如您所知,解决方法是使用
d.items()
(在容器的独立副本上循环)而不是
d.iteritems()
(使用相同的底层容器)


可以修改dict现有索引处的值,但在新索引处插入值(例如,
d[g(k)]=v
)可能不起作用。

Python文档页面(for)中明确提到

在字典中添加或删除条目时使用
iteritems()

同样地,对于


对于
iter(d)
d.iterkeys()
d.itervalues()
,我甚至可以说它对
中的k,v都有作用。items():
(我记不清
对于
有什么作用,但如果实现调用
iter(d)
,我不会感到惊讶).

我遇到了同样的问题,我使用以下步骤解决了这个问题

Python列表可以被迭代,即使您在迭代过程中对其进行了修改。 所以对于下面的代码,它将无限打印1

for i in list:
   list.append(1)
   print 1
所以,协作使用list和dict可以解决这个问题

d_list=[]
 d_dict = {} 
 for k in d_list:
    if d_dict[k] is not -1:
       d_dict[f(k)] = -1 # rather than deleting it mark it with -1 or other value to specify that it will be not considered further(deleted)
       d_dict[g(k)] = v # add a new item 
       d_list.append(g(k))

我有一个包含Numpy数组的大字典,所以@murgatroid99建议的dict.copy().keys()方法是不可行的(尽管它有效)。相反,我只是将keys_视图转换为一个列表,它工作得很好(在Python 3.4中):


我意识到这并不像上面的答案那样深入到Python内部工作的哲学领域,但它确实为所述问题提供了一个实用的解决方案。

今天我有一个类似的用例,但不是简单地在循环开始时具体化字典上的键,我希望对dict的更改能够影响dict的迭代,这是一个有序dict

我最终构建了以下例程,也可以是:


docstring说明了该用法。此函数可以用来代替上面的
d.iteritems()
,以达到预期效果。

Python 3您应该:

prefix = 'item_'
t = {'f1': 'ffw', 'f2': 'fca'}
t2 = dict() 
for k,v in t.items():
    t2[k] = prefix + v
或使用:

t2 = t1.copy()

您永远不应该修改原始字典,它会导致混乱以及潜在的bug或运行时错误。除非您只是在字典中添加新的键名。

可能重复的See我已经尝试过这样做,如果您保持初始dict大小不变,例如,替换任何键/值而不是删除它们,则此代码不会抛出异常。我不同意“很明显,如果它损坏了,如何修复它”对于搜索这个主题的每个人(包括我自己),我希望被接受的答案至少涉及到这一点。我可以理解为什么你可能期望
{11:ax',12:bx',13:cx'}
,但是21,22,23应该给你关于实际发生了什么的线索:你的循环通过了项目1,2,3,11,12,13但在第二轮新项目插入到您已经迭代过的项目之前时,没有成功地拾取它们。更改
h()
以返回
x+5
,您将获得另一个x:
'axxx'
等或'x+3',您将获得华丽的
'axxxxx'
是的,我恐怕是我的错误-正如您所说,我的预期输出是
{11:'ax 12:'bx',13:'cx'}
,因此我将更新我的帖子。无论哪种方式,这显然都不是定义良好的行为。我在回答中添加了Python 3。仅供参考,Py2的
d.items()
到Py3的直译(例如
2to3
)是
list(d.items())
,尽管
d.copy().items()
可能具有相当的效率。如果dict对象非常大,则是d.copy().items>()efficiet?我想这对我来说是一个关键答案。很多用例都会有一个过程插入东西,另一个过程清理/删除它们,所以建议使用d.items()Python 3注意事项与Python 3注意事项相关的更多信息可以在前面提到的Python 2 dict方法的语义等价物中找到。“可以修改dict现有索引处的值”--你有这方面的参考资料吗?@JonathonReinhart:没有,我没有这方面的参考资料,但我认为这在Python中是相当标准的。例如,Alex Martelli是一名Python核心开发人员。为了社区的利益,我会说我使用了非常多的代码片段。我想,既然我没有遇到运行时错误
prefix = 'item_'
t = {'f1': 'ffw', 'f2': 'fca'}
t2 = dict() 
for k,v in t.items():
    t2[k] = prefix + v
t2 = t1.copy()