Как исправить эту ошибку Python? RuntimeError: словарь изменил размер во время итерации - PullRequest
3 голосов
/ 16 мая 2010

это дает мне эту ошибку:

Exception in thread Thread-163:
Traceback (most recent call last):
  File "C:\Python26\lib\threading.py", line 532, in __bootstrap_inner
    self.run()
  File "C:\Python26\lib\threading.py", line 736, in run
    self.function(*self.args, **self.kwargs)
  File "C:\Users\Public\SoundLog\Code\Código Python\SoundLog\SoundLog.py", line 337, in getInfo
    self.data1 = copy.deepcopy(Auxiliar.DataCollection.getInfo(1))
  File "C:\Python26\lib\copy.py", line 162, in deepcopy
    y = copier(x, memo)
  File "C:\Python26\lib\copy.py", line 254, in _deepcopy_dict
    for key, value in x.iteritems():
RuntimeError: dictionary changed size during iteration

во время выполнения моей программы на Python.

Как мне этого избежать?

Заранее спасибо;)

Ответы [ 3 ]

13 голосов
/ 16 мая 2010

Обычный совет, согласно другим ответам, состоит в том, чтобы избегать использования iteritems (используйте items вместо). Это, конечно, вариант , а не в вашем случае, поскольку вызов iteritems выполняется от вашего имени в глубине системного вызова.

Поэтому, я бы предложил, если Auxiliar.DataCollection.getInfo(1) возвращает словарь (который меняется во время копирования), это то, что вы изменили свой deepcopy вызов на:

self.data1 = copy.deepcopy(dict(Auxiliar.DataCollection.getInfo(1)))

Это берет «снимок» рассматриваемого диктанта, и снимок не изменится, так что все будет в порядке.

Если Auxiliar.DataCollection.getInfo(1) действительно не возвращает диктовку, а какой-то более сложный объект, который включает в себя диктовки в качестве предметов и / или атрибутов, это будет немного сложнее, поскольку эти диктовки - то, что нужно сделать снимок. Тем не менее, невозможно быть более конкретным в этом случае, так как вы абсолютно не даете нам понять, что код, который составляет этот важный Auxiliar.DataCollection.getInfo(1) вызов! -)

2 голосов
/ 06 мая 2012

Хотя этой теме уже почти 2 года, у меня возникла похожая проблема:

У меня есть система типа производитель / потребитель, основанная на модуле очереди. Метод выполнения моего рабочего класса определен так:

def run(self):
    while True:
    a, b, c = Worker._Queue.get()
    # do some stuff
    ...
    self.notify() # notify observers
    Worker._Queue.task_done()

Основной класс определяет метод обновления для уведомления работника о сборе данных и их сохранения в словаре. Поскольку несколько потоков могут изменить словарь в главном классе, этот «критический раздел» заблокирован

def update(self, worker):
    Main.indexUpdateLock.acquire()
    # get results of worker
    index = worker.getIndex()
    # copy workers index into the main index
    try:
        for i in index:
            if i in self._index:
                self._index[i] += index[i]
            else:
                self._index[i] = index[i]
    finally:
        # index copied - release the lock
        Main.indexUpdateLock.release()

Теперь это работает в большинстве случаев - но иногда как-то «для i in index:» в методе обновления Main выдает RuntimeError: dictionary, изменяющий размер во время итерации. indexUpdateLock определяется как threading.Lock () или threading.RLock () - поведение не изменяется ни в коем случае, если я его определяю.

для i в dict (index): действительно решает проблему, но поскольку индекс может содержать несколько тысяч записей, его копирование на самом деле не увеличивает производительность, поэтому я пытаюсь скопировать эти значения напрямую.

Хотя обновление определено в Main, посредством вызова notify () в потоке работника, обновление должно выполняться и в потоке работника, и, следовательно, task_done () будет выполняться только после завершения notify () или более поздней версии update (). обработка. И благодаря определению критической секции только одна нить может одновременно выполнять эту область - или у меня есть некоторые логические ошибки здесь? Я действительно не вижу, откуда происходит изменение индекса работника, так как единственный доступ к индексу находится в Main.update () и в Worker, но до тех пор, пока task_done () не выполнится, никакой другой метод не изменяет индекс внутри Worker


редактировать: Хорошо, исправлена ​​проблема, которая была вызвана HTMLParser внутри Worker, который отправил одну дополнительную запись, хотя источник был уже закрыт - хотя странное поведение. Хотя для i в index: все еще выдает ошибки для i в index.keys (): нет, поэтому я буду придерживаться этого

0 голосов
/ 16 мая 2010

Похоже, вы добавляете или удаляете что-то из словаря, который вы пытаетесь повторить. Это запрещено на большинстве языков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...