如何解决这个python错误? RuntimeError:字典在迭代期间改变了大小

时间:2010-05-16 18:02:18

标签: python

它给了我这个错误:

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 个答案:

答案 0 :(得分:13)

根据其他答案,正常建议是避免使用iteritems(改为使用items)。当然,在您的情况下,是一个选项,因为iteritems电话是在您的系统调用的深处代表您完成的。

因此,我建议,假设Auxiliar.DataCollection.getInfo(1)返回字典(在复制过程中正在更改的字典)是您将deepcopy调用更改为:

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

这会拍摄相关字典的“快照”,快照不会改变,所以你会没事的。

如果Auxiliar.DataCollection.getInfo(1) 返回一个字典,而是一些更复杂的对象,其中包含dicts作为项目和/或属性,那将会更复杂一些,因为那些dicts是什么你需要快照。但是,在这种情况下,不可能更具体,因为你完全不知道组成那个关键的Auxiliar.DataCollection.getInfo(1)调用的代码! - )

答案 1 :(得分:2)

虽然这个帖子已有近2年的历史,但我遇到了类似的问题:

我有一个基于Queue模块的类似生产者/消费者的系统。我的工人级'run-method定义如下:

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

main-class定义了一个update-method,用于通知工作者收集数据并将其存储在字典中。由于多个线程可能会更改主类中的字典,因此“关键部分”被锁定

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()

现在这在大多数情况下都有效 - 但是在某些情况下,有时候'对于我在索引中:'在主的update-method中会抛出一个RuntimeError:字典在迭代期间改变了大小。 indexUpdateLock定义为threading.Lock()或threading.RLock() - 行为不会改变我定义它的方式。

for d in dict(index):确实解决了问题,但由于索引可能包含数千个条目,复制它并不会真正提高性能,因此我试图直接复制这些值。

虽然更新是在Main中定义的,但是通过在worker的线程中调用notify(),update也应该在worker的线程中执行,因此task_done()只有在notify()或更新后的update()完成时才会执行处理。通过临界区的定义,一次只允许一个线程执行该区域 - 或者我在这里有一些逻辑错误?我真的没有看到工作者索引的更改来自哪里,因为唯一的索引访问权限是在Main.update()和Worker中,但是直到task_done()没有执行,没有其他方法修改工作者内部的索引


编辑: 好的,修复了由于发送了一个额外条目的工作者内部的HTMLParser引起的问题,尽管源已经关闭 - 虽然有奇怪的行为。虽然对于索引中的i:仍然在index.keys()中为i生成错误:没有,所以我会坚持这个

答案 2 :(得分:0)

听起来您正在尝试迭代的字典中添加或删除某些内容。大多数语言都不允许这样做。