Python 如何避免“RuntimeError:dictionary在迭代期间更改了大小”错误?
我已经检查了所有其他问题的相同错误,但没有找到有用的解决办法=/ 我有一本清单字典:Python 如何避免“RuntimeError:dictionary在迭代期间更改了大小”错误?,python,list,dictionary,loops,Python,List,Dictionary,Loops,我已经检查了所有其他问题的相同错误,但没有找到有用的解决办法=/ 我有一本清单字典: d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]} 其中一些值为空。在创建这些列表的最后,我想在返回字典之前删除这些空列表。目前,我正尝试按如下方式执行此操作: for i in d: if not d[i]: d.pop(i) 但是,这给了我运行时错误。我知道,在遍历字典时,不能添加/删除字典中的元素……那么解决方法是什么呢?在Python 3
d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}
其中一些值为空。在创建这些列表的最后,我想在返回字典之前删除这些空列表。目前,我正尝试按如下方式执行此操作:
for i in d:
if not d[i]:
d.pop(i)
但是,这给了我运行时错误。我知道,在遍历字典时,不能添加/删除字典中的元素……那么解决方法是什么呢?在Python 3.x和2.x中,可以使用来强制创建密钥副本:
for i in list(d):
在Python 2.x中,调用创建了一个密钥副本,您可以在修改dict时对其进行迭代:
但是请注意,在Python3.x中,第二种方法对您的错误没有帮助,因为键返回a而不是将键复制到列表中。只需使用字典理解将相关项复制到新的dict中即可
>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.iteritems() if v}
>>> d
{'a': [1], 'b': [1, 2]}
在Python3中实现了这一点
>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.items() if v}
>>> d
{'a': [1], 'b': [1, 2]}
首先,我会尽量避免插入空列表,但通常会使用:
d = {k: v for k,v in d.iteritems() if v} # re-bind to non-empty
如果在2.7之前:
d = dict( (k, v) for k,v in d.iteritems() if v )
或者只是:
empty_key_vals = list(k for k in k,v in d.iteritems() if v)
for k in empty_key_vals:
del[k]
对于Python 3:
{k:v for k,v in d.items() if v}
您只需使用复制: 通过这种方式,您可以迭代原始字典字段,并动态更改所需的dict d dict。 这是每个python版本上的工作,因此更清晰
In [1]: d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}
In [2]: for i in d.copy():
...: if not d[i]:
...: d.pop(i)
...:
In [3]: d
Out[3]: {'a': [1], 'b': [1, 2]}
运行时错误的原因是,当数据结构在迭代过程中发生更改时,您无法对其进行迭代 实现所需功能的一种方法是使用list附加要删除的键,然后在遍历列表时使用dictionary上的pop函数删除标识的键
d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}
pop_list = []
for i in d:
if not d[i]:
pop_list.append(i)
for x in pop_list:
d.pop(x)
print (d)
对于这种情况,我喜欢制作一个深度副本,并在修改原始dict时循环该副本
如果查找字段在列表中,则可以在列表的for循环中枚举,然后将位置指定为索引,以访问原始目录中的字段。在for循环过程中更改词典时,不能遍历词典。对列表进行转换并迭代该列表,这对我很有用
for key in list(d):
if not d[key]:
d.pop(key)
Python3不允许在使用字典上方的for循环进行迭代时删除。有多种选择可供选择;一个简单的方法是更改以下行
for i in x.keys():
与
这对我很有用:
dict = {1: 'a', 2: '', 3: 'b', 4: '', 5: '', 6: 'c'}
for key, value in list(dict.items()):
if (value == ''):
del dict[key]
print(dict)
# dict = {1: 'a', 3: 'b', 6: 'c'}
将字典项强制转换为列表将创建其项的列表,因此您可以对其进行迭代并避免运行时错误。dictc={stName:asas}
keys=dictc.keys
对于输入列表键:
dictc[key.upper]=“新值”
印刷品
避免在迭代错误期间更改字典大小 只需将“list”与“.items”一起使用,下面是一个简单的示例:
my_dict = {
'k1':1,
'k2':2,
'k3':3,
'k4':4
}
print(my_dict)
for key, val in list(my_dict.items()):
if val == 2 or val == 4:
my_dict.pop(key)
print(my_dict)
+++
输出:
{'k1':1,'k2':2,'k3':3,'k4':4}
{'k1':1,'k3':3}
+++
这只是一个示例,并根据您的案例/需求进行更改,
我希望这会有所帮助。+1:最后一个选项很有趣,因为它只复制需要删除的项目的键。如果相对于dict的大小,只有少量项目需要删除,那么这可能会提供更好的性能。@MarkByers是的-如果有大量项目需要删除,那么将dict重新绑定到经过过滤的新项目是更好的选择。人们总是期望结构应该如何工作。重新绑定的危险在于,如果程序中的某个地方有一个对象引用了旧的dict,它将看不到更改。如果你确定不是这样的话,那么肯定。。。这是一个合理的方法,但重要的是要理解,这与修改原来的格言并不完全相同。@MarkByers非常好的观点——你和我都知道这一点,还有无数其他的,但这并不明显。我会把钱放在桌子上,它也不会在后面咬你:避免插入空条目是一个很好的方法。我相信你的意思是“调用键复制可以重复的键”,也就是复数键,对吗?否则,如何迭代单个键?顺便说一句,我不是吹毛求疵,我真的很想知道这是否是键或键或元组,而不是列表,因为它更快。为了澄清python 3.x的行为,d.keys返回一个iterable而不是迭代器,这意味着它是字典键的直接视图。一般来说,在Python3.x中使用for i in d.keys确实可以工作,但是因为它在字典键的可编辑视图上迭代,所以在循环期间调用d.pop会导致与您发现的相同的错误。因为listd中的i模拟了Python2在迭代之前将键复制到列表中的低效行为,对于像您这样的特殊情况,当您要删除内部目录中的对象时,python3解决方案不起作用。例如,您在目录a中有dic a和dict B。如果您要删除目录B中的对象,则在python3.x中会发生错误,listd.keys会创建与listd相同的输出,调用list on
dict返回键。钥匙打电话虽然不贵,但没有必要。d.iteritems给了我一个错误。我用d.items来代替——用python3解决OP的问题。然而,在多线程代码中碰到这个运行时错误后,任何人都会意识到,cPython的吉尔也可以在列表理解的中间被释放,而你必须以不同的方式来修复它。在Python 2.7中也为我工作过。从这里的所有答案来看,对于我来说,这是最简单和pythonic.quick和最简单的修复方法,在这个线程上列出的所有选项中,到目前为止。谢谢@singrium
dict = {1: 'a', 2: '', 3: 'b', 4: '', 5: '', 6: 'c'}
for key, value in list(dict.items()):
if (value == ''):
del dict[key]
print(dict)
# dict = {1: 'a', 3: 'b', 6: 'c'}
my_dict = {
'k1':1,
'k2':2,
'k3':3,
'k4':4
}
print(my_dict)
for key, val in list(my_dict.items()):
if val == 2 or val == 4:
my_dict.pop(key)
print(my_dict)