在Python中,我可以在遍历字典时删除字典中的项吗?

我想从字典中删除不符合特定条件的元素,而不是创建一个全新的字典。以下是一个好的解决方案,还是有更好的方法?

for k, v in mydict.items():
    if k == val:
        del mydict[k]

当前回答

在迭代集合时不能修改集合。这种方式是疯狂的——最明显的是,如果你被允许删除和删除当前项,迭代器将不得不移动(+1),而下一次调用next将超出(+2),所以你最终会跳过一个元素(在你删除的元素后面的那个元素)。你有两个选择:

Copy all keys (or values, or both, depending on what you need), then iterate over those. You can use .keys() et al for this (in Python 3, pass the resulting iterator to list). Could be highly wasteful space-wise though. Iterate over mydict as usual, saving the keys to delete in a seperate collection to_delete. When you're done iterating mydict, delete all items in to_delete from mydict. Saves some (depending on how many keys are deleted and how many stay) space over the first approach, but also requires a few more lines.

其他回答

对于Python 3+:

>>> mydict
{'four': 4, 'three': 3, 'one': 1}

>>> for k in list(mydict.keys()):
...     if mydict[k] == 3:
...         del mydict[k]

>>> mydict
{'four': 4, 'one': 1}

其他答案在Python 2中工作得很好,但在Python 3中会引发RuntimeError:

RuntimeError:在迭代过程中字典改变了大小。

这是因为mydict.keys()返回的是一个迭代器而不是一个列表。 正如在评论中指出的那样,只需将mydict.keys()转换为逐个列表的列表(mydict.keys()),它就应该工作。


对于Python 2:

在控制台中进行的一个简单测试显示,在遍历字典时不能修改它:

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}

>>> for k, v in mydict.iteritems():
...    if k == 'two':
...        del mydict[k]

------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

正如delnan的回答中所述,当迭代器试图移动到下一个条目时,删除条目会导致问题。相反,使用keys()方法获取键的列表并使用它:

>>> for k in mydict.keys():
...    if k == 'two':
...        del mydict[k]

>>> mydict
{'four': 4, 'three': 3, 'one': 1}

如果你需要根据items的值进行删除,请使用items()方法:

>>> for k, v in mydict.items():
...     if v == 3:
...         del mydict[k]

>>> mydict
{'four': 4, 'one': 1}

我在Python3中尝试了上述解决方案,但在字典中存储对象时,这一个似乎是唯一适合我的解决方案。基本上,您可以创建dict()的副本,并在删除原始字典中的条目的同时遍历该副本。

        tmpDict = realDict.copy()
        for key, value in tmpDict.items():
            if value:
                del(realDict[key])

使用列表(mydict)是最干净的:

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k in list(mydict):
...     if k == 'three':
...         del mydict[k]
... 
>>> mydict
{'four': 4, 'two': 2, 'one': 1}

这对应于列表的并行结构:

>>> mylist = ['one', 'two', 'three', 'four']
>>> for k in list(mylist):                            # or mylist[:]
...     if k == 'three':
...         mylist.remove(k)
... 
>>> mylist
['one', 'two', 'four']

它们都可以在python2和python3中工作。

你也可以分两步来做:

remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]

我最喜欢的方法通常是创建一个新词典:

# Python 2.7 and 3.x
mydict = { k:v for k,v in mydict.items() if k!=val }
# before Python 2.7
mydict = dict((k,v) for k,v in mydict.iteritems() if k!=val)

如果想要删除的项总是在dict迭代的“开始”,有一种方法可能是合适的

while mydict:
    key, value = next(iter(mydict.items()))
    if should_delete(key, value):
       del mydict[key]
    else:
       break

“开头”只保证在某些Python版本/实现中是一致的。例如,来自Python 3.7新提示

dict对象的插入顺序保存特性已被声明为Python语言规范的正式组成部分。

这种方法避免了许多其他答案所建议的字典副本,至少在Python 3中是这样。