修改Python字典,同时迭代它
假设我们有一个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
迭代它。
这是很好的定义? 你能提供一些参考来支持你的答案吗?
(这很明显,如果它被破坏,如何解决这个问题,所以这不是我所追求的angular度。)
Python文档页面( Python 2.7 )明确提到
在添加或删除字典中的条目时使用
iteritems()
可能会引发RuntimeError
或无法遍历所有条目。
对于Python 3也是如此 。
这也适用于iter(d)
, d.iterkeys()
和d.itervalues()
,我会尽可能地说for k, v in d.items():
我不能记得确切地说是做什么for
,但是如果实现叫iter(d)
),我不会感到惊讶。
亚历克斯·马尔泰利在这里权衡这个。
在容器上循环时更换容器(例如字典)可能不安全。 所以del d[f(k)]
可能不安全。 如您所知,解决方法是使用d.items()
(以遍历容器的独立副本)而不是d.iteritems()
(它使用相同的基础容器)。
在dict的现有索引处修改值是可以的,但是在新索引处插入值(例如d[g(k)]=v
)可能不起作用。
你不能这样做,至less用d.iteritems()
。 我试过了,Python失败了
RuntimeError: dictionary changed size during iteration
如果你使用d.items()
,那么它的工作原理。
在Python 3中, d.items()
是字典的视图,就像Python 2中的d.iteritems()
。要在Python 3中执行此操作,请使用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),并抛出一个exception(迭代期间字典改变大小)。
第二个例子调用h(k)并且不会抛出exception,但输出:
{21: 'axx', 22: 'bxx', 23: 'cxx'}
其中,看代码,似乎是错误的 – 我会有这样的预期:
{11: 'ax', 12: 'bx', 13: 'cx'}
我有一个包含Numpy数组的大字典,所以@ murgatroid99build议的dict.copy()。keys()是不可行的(尽pipe它工作正常)。 相反,我只是将keys_view转换成了一个列表,它工作正常(在Python 3.4中):
for item in list(dict_d.keys()): temp = dict_d.pop(item) dict_d['some_key'] = 1 # Some value
我意识到这并不是像上面的答案那样深入Python的内部工作的哲学领域,但它确实提供了一个解决问题的实际解决scheme。
我得到了同样的问题,我用下面的程序来解决这个问题。
即使您在迭代它时修改了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))