Простой тест на консоли показывает, что вы не можете изменять словарь при повторении через него:
>>> 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
Как указано в ответе Делнана, удаление записей вызывает проблемы, когда итератор пытается перейти к следующей записи , Вместо этого используйте метод keys()
, чтобы получить список ключей и работать с ним:
>>> for k in mydict.keys():
... if k == 'two':
... del mydict[k]
...
>>> mydict
{'four': 4, 'three': 3, 'one': 1}
Если вам нужно удалить на основе значения элементов, используйте вместо этого метод items()
:
>>> for k, v in mydict.items():
... if v == 3:
... del mydict[k]
...
>>> mydict
{'four': 4, 'one': 1}
EDIT:
Выше не будет работать для Python3 и даст RuntimeError
.
RuntimeError: словарь изменил размер во время итерации.
blockquote>Это происходит потому, что
mydict.keys()
возвращает итератор, а не список. Как указано в комментариях, просто конвертируйтеmydict.keys()
в список поlist(mydict.keys())
, и он должен работать.
Вы можете использовать понимание словаря.
d = {k:d[k] for k in d if d[k] != val}
С python3, итерация на dic.keys () приведет к увеличению ошибки размера словаря. Вы можете использовать этот альтернативный способ:
Протестировано с помощью python3, оно отлично работает и «Измененный размер словаря во время итерации» не поднимается:
my_dic = { 1:10, 2:20, 3:30 }
# Is important here to cast because ".keys()" method returns a dict_keys object.
key_list = list( my_dic.keys() )
# Iterate on the list:
for k in key_list:
print(key_list)
print(my_dic)
del( my_dic[k] )
print( my_dic )
# {}
Я использую его, когда, из словаря с использованием лота памяти я хочу построить другой словарь (содержащий модификацию первого) без выполнения «копирования» и перегрузки ОЗУ.
Итерации вместо копии, например, возвращаемой функцией items()
:
for k, v in list(mydict.items()):
del v
напрямую, поэтому вы сделали копию каждого v, которую вы никогда не собираетесь использовать, и вам все равно нужно получить доступ к элементам по ключу. dict.keys()
- лучший выбор.
– Josh Caswell
22 March 2011 в 03:21
v
в качестве критерия для удаления.
– Ignacio Vazquez-Abrams
22 March 2011 в 08:00
dict.items()
возвращает итератор, а не копию. См. Комментарий к ответу Блэра , который (к сожалению) также предполагает семантику Python 2.
– Cecil Curry
22 February 2016 в 06:37
Я попробовал вышеуказанные решения в Python3, но этот, кажется, единственный, кто работает для меня при хранении объектов в dict. В основном вы делаете копию своего dict () и перебираете ее, удаляя записи в исходном словаре.
tmpDict = realDict.copy()
for key, value in tmpDict.items():
if value:
del(realDict[key])
Вы также можете сделать это в два этапа:
remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]
Мой любимый подход обычно состоит в том, чтобы просто создать новый dict:
# 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)
remove
.
– max
26 January 2012 в 19:28
for k in [k for k in mydict if k == val]: del mydict[k]
– AXO
16 January 2017 в 12:14
Вы можете сначала создать список ключей для удаления, а затем перебрать этот список, удалив их.
dict = {'one' : 1, 'two' : 2, 'three' : 3, 'four' : 4}
delete = []
for k,v in dict.items():
if v%2 == 1:
delete.append(k)
for i in delete:
del dict[i]
Чистое использование list(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.
Вы не можете изменять коллекцию при ее итерации. Таким образом, безумие - в первую очередь, если вам разрешено удалять и удалять текущий элемент, то итератору нужно будет двигаться дальше (+1), а следующий вызов next
приведет вас к тому, что (+2), поэтому вы закончите тем, что пропустите один элемент (тот, который прямо за тем, который вы удалили). У вас есть два варианта:
.keys()
et al для этого (в Python 3 передать результирующий итератор на list
). Однако может быть очень расточительным по пространству. mydict
, сохраняя ключи для удаления в отдельной коллекции to_delete
. Когда вы закончите повтор mydict
, удалите все элементы в to_delete
из mydict
. Сохраняет некоторые (в зависимости от того, сколько ключей удалено и сколько осталось) пробегает первый подход, но также требует еще несколько строк. You can't modify a collection while iterating it.
это правильно для диктов и друзей, но вы можете изменять списки во время итерации: L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]
– Nils
29 February 2016 в 17:42
can't
является правильным только для dict и друзей, в то время как для списков должно быть shouldn't
.
– Nils
29 February 2016 в 20:20
for k, v in list(mydict.items()):
, который отлично работает на Python 3. То же самое дляkeys()
становитсяlist(keys())
. – Walter Mundt 15 August 2012 в 18:59RuntimeError: dictionary changed size during iteration
– Tomáš Zato 18 December 2016 в 03:56for k in list(mydict.keys()):
, поскольку python3 делает метод keys () итератором, а также запрещает удаление элементов dict во время итерации. Добавив вызов list (), вы превращаете итератор ключей () в список. Поэтому, когда вы находитесь в теле цикла for, вы больше не итерации по самому словарю. – Geoff Crompton 23 March 2017 в 00:12