RuntimeError: словарь изменил размер во время итерации - во время итерации с символами по умолчанию по умолчанию - PullRequest
3 голосов
/ 06 января 2012

Отвечая на конкретный вопрос здесь, в SO, я наткнулся на странную проблему, которую я не мог объяснить. К сожалению, первые две страницы поиска Google вернули одну SO страницу, которая также оказалась бесполезной.

Код проблемы

>>> somedata=[random.randint(1,1000) for i in xrange(1,10000)]
>>> somehash=collections.defaultdict(int)
>>> for d in somedata:
    somehash[d]+=1      
>>> maxkey=0
>>> for k,v in somehash.iteritems():
    if somehash[maxkey] > v:
        maxkey=k            

Traceback (most recent call last):
  File "<pyshell#700>", line 1, in <module>
    for k,v in somehash.iteritems():
RuntimeError: dictionary changed size during iteration
>>> for k,v in somehash.iteritems():
    if somehash[maxkey] > v:
        maxkey=k
>>>

И по какой-то странной причине, когда я в первый раз перебираю словарь, Python создает истерики, но последующие исполнения хороши, как вы можете видеть в примере, когда я перебирал словарь впервые, он Ошибка времени выполнения, но в следующий раз он не пожаловался.

Есть идеи, что может пойти не так?

На всякий случай, если потребуется

>>> sys.version_info
sys.version_info(major=2, minor=7, micro=0, releaselevel='final', serial=0)
>>> sys.version
'2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)]'

OS: Microsoft Windows [Version 6.1.7601] (Windows 7)

Ответы [ 3 ]

11 голосов
/ 06 января 2012

Добавление или удаление элементов словаря во время итерации по нему является ошибкой. Поскольку somehash является defaultdict, даже то, что похоже на доступ только для чтения в строке

if somehash[maxkey] > k:

может добавить новый ключ - в результате вы столкнулись с ошибкой.

3 голосов
/ 09 апреля 2013

Как объяснил Свен, ошибка, с которой вы сталкиваетесь, связана с тем, как работает defaultdict.При выполнении поиска в defaultdict, если ключ еще не существует, извлекается значение по умолчанию (отсюда и имя), и ключ добавляется в словарь (со значением по умолчанию).Это источник вашего RuntimeError.

. Чтобы избежать этой проблемы, вы можете сделать следующее:

for k, v in somehash.items():
    if somehash[maxkey] > v:
        maxkey = k

Основное отличие в том, что somehash.items() возвращает список (ключ,значение), так что вы на самом деле перебираете этот список, а не сам somehash.То же самое касается .keys() против .iterkeys().

0 голосов
/ 27 августа 2013

Вы генерируете 9999 (несколько) случайных целых чисел от 1 до 1000 , хранящихся в somedata, который используется в качестве ключа для somehash, для хранения вхождения чисел в некоторые данные.

Как и maxkey=0, этот ключ никогда не будет существовать. Поскольку вы используете defaultdict, , когда каждый ключ встречается в первый раз, запись автоматически создается с использованием функции default_factory, которая возвращает пустой список , таким образом, правильно выбрасывая ошибка во время итерации таким образом, который * FastTurtle * уже указал.

Используйте метод get для безопасного извлечения элемента.

import random
import collections

somedata=[random.randint(1,1000) for i in xrange(1,10000)]
somehash=collections.defaultdict(int)
for d in somedata:
   somehash[d]+=1 

maxkey=0
for k,v in somehash.iteritems():
   if somehash.get(maxkey) > v:
       maxkey=k 
       print k,v  

Я вижу, что вы используете Python 2.7, который имеет новый класс коллекции с именем Counter, для подсчета хеш-объектов. Использование Counter должно выполняться быстрее, чем приведенный выше код, и сокращает ваш код до:

somedata=[random.randint(1,1000) for i in xrange(1,10000)]
somehash=collections.Counter(somedata)
...