【问题标题】:dictionary size changed during iteration (Runtime error)迭代期间字典大小更改(运行时错误)
【发布时间】:2019-07-14 11:19:43
【问题描述】:

我得到 RuntimeError: dictionary changed size during iteration,我查看了一些堆栈溢出帖子,发现当您在字典循环(插入/删除)时修改字典的大小时会发生这种情况。

但就我而言,我只是在遍历字典,所以我不确定为什么会出现错误。

我发现在使用非集合字典时我没有遇到任何问题,但这使得添加新顶点比使用集合复杂得多。

我知道我可能会制作字典的深层副本并对其进行迭代,但我想首先了解为什么我首先会收到此错误。

我在下面的示例中删除了大部分非必要的代码。

from collections import defaultdict 


class Graph: 

    def __init__(self,vertices): 

        self.graph = defaultdict(list)  

    def addEdge(self,u,v): 
        self.graph[u].append(v) 

    def fillOrder(self,v,visited, stack): 

        visited.add(v)
        for neighbour in self.graph[v]:
          if neighbour not in visited:
            self.fillOrder(neighbour, visited, stack)
        stack.append(v)


    def printSCCs(self): 

        stack = [] 

        visited = set()

        for key in self.graph:
          print(key)
          self.fillOrder(key, visited, stack)

g = Graph(5) 
g.addEdge(1, 0) 
g.addEdge(0, 2) 
g.addEdge(2, 1) 
g.addEdge(0, 3) 
g.addEdge(3, 4) 
g.printSCCs() 

我希望不会抛出错误,并且堆栈会被图中的顶点填充。

【问题讨论】:

    标签: python python-3.x dictionary recursion


    【解决方案1】:

    您使用的是defaultdict,因此如果您尝试访问不存在的条目,则会在隐式插入中出现。

    特别是:

    def fillOrder(self,v,visited, stack): 
        # ...
        for neighbour in self.graph[v]:
            # ...
    

    您的密钥v 不能保证存在,因此self.graph[v] 的访问会导致将新条目添加到字典中。如果您将defaultdict 替换为普通字典并在addEdge 中按需创建新列表,那么失败的原因就更明显了:

    1
    Traceback (most recent call last):
      File "test.py", line 38, in <module>
        g.printSCCs()
      File "test.py", line 30, in printSCCs
        self.fillOrder(key, visited, stack)
      File "test.py", line 21, in fillOrder
        self.fillOrder(neighbour, visited, stack)
      File "test.py", line 21, in fillOrder
        self.fillOrder(neighbour, visited, stack)
      File "test.py", line 21, in fillOrder
        self.fillOrder(neighbour, visited, stack)
      File "test.py", line 19, in fillOrder
        for neighbour in self.graph[v]:
    KeyError: 4
    

    如果您想保证两个边缘端点都在字典中,您可能需要修改 addEdge 来执行此操作:

    self.graph[u].append(v) 
    self.graph[v].append(u) 
    

    【讨论】:

    • 我从 printSCC 调用 FillOrder,里面有一个循环,遍历 self.graph 中的每个键,那么 v 怎么可能不存在?
    • 当您添加端点为“U”和“V”的边时,您只需将“U”添加到字典中。您同时迭代“U”和“V”,因此任何未将“V”作为“U”值添加到另一条边的边都将失败。
    猜你喜欢
    • 1970-01-01
    • 2019-12-02
    • 1970-01-01
    • 2021-11-21
    • 2023-04-02
    • 2021-07-05
    相关资源
    最近更新 更多