Python 如何避免;运行时错误:字典在迭代过程中更改了大小;错误?

Python 如何避免;运行时错误:字典在迭代过程中更改了大小;错误?,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):
在Python2.x中,调用创建了一个键的副本,您可以在修改
dict
时对其进行迭代:

for i in d.keys():

但是请注意,在Python3.x中,第二种方法对您的错误没有帮助,因为
keys
返回一个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()]=“新值”
打印(str(dictc))
避免“迭代错误期间更改字典大小” 只需将“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(不是迭代器),这意味着它是字典键的直接视图。使用
for i in d.keys()
通常在Python3.x中确实有效,但由于它在字典键的可编辑视图上迭代,因此在循环期间调用
d.pop()
会导致与您发现的错误相同的错误<代码>对于列表(d)中的i
模拟了Python2在迭代之前将键复制到列表中的低效行为,对于像您这样的特殊情况。当您要删除内部目录中的对象时,python3解决方案不起作用。例如,您的目录a中有dic a和dic B。如果您要删除目录B中的对象,则python3.x中会出现错误,
list(d.keys())
创建与
list(d)
相同的输出,在
dict
上调用
list
,返回键。
keys
调用(虽然没有那么昂贵)是不必要的。
d.iteritems()
给了我一个错误。我改用了
d.items()
——用python3解决OP的问题。然而,在多线程代码中碰到这个运行时错误后,任何人都会意识到,cPython的吉尔也可以在列表理解的中间被释放,而你必须以不同的方式来修复它。在Python 2.7中也为我工作过。从这里的所有答案来看,对于我来说,这是最简单和pythonic.quick和最简单的修复方法,在这个线程上列出的所有选项中,到目前为止。谢谢@singrium
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)