You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python 3 RuntimeError求助:遍历字典时修改大小触发报错

解决字典遍历中修改引发的RuntimeError问题

你遇到的RuntimeError: dictionary changed size during iteration是Python里很典型的字典遍历陷阱——在Python 3中,dict.keys()返回的是动态视图对象,它会实时同步字典的变化。当你在遍历这个视图的过程中,给字典新增了键(比如self.enemydict[(goingTo[0], goingTo[1])] = ...),字典的大小发生改变,遍历就会直接抛出这个错误。

下面是针对性的解决方案和代码优化建议:

1. 核心修复:使用静态键列表遍历

把遍历的键转换成静态列表,这样你遍历的是字典键的副本,后续字典的变化不会影响循环执行。修改这一行:

keys = self.enemydict.keys()

改为:

keys = list(self.enemydict.keys())

2. 清理无效键值对

你当前把旧位置的键值设为' ',这并没有删除旧键,会导致字典里积累大量无效的键值对。正确的做法是直接删除旧键:

# 替换原来的赋值语句
# self.enemydict[key] = ' '
del self.enemydict[key]

3. 修复多次移动的逻辑漏洞

如果leap大于1,你的代码会重复使用初始的key(旧位置)进行移动,但此时旧键已经被删除了。需要在每次移动后更新key为新位置,确保后续移动基于当前最新位置。

修改后的完整代码示例

def moveEnemies(self):
    # 生成键的静态副本,避免遍历中字典变化触发错误
    keys = list(self.enemydict.keys())
    for key in keys:
        # 先检查当前键对应的是否还是有效敌人对象
        enemy = self.enemydict.get(key)
        if enemy == ' ' or enemy is None:
            continue
        
        leap = enemy.leap
        if not enemy.attacked:
            enemy.counter -= 1
            if enemy.counter <= 0 and not enemy.attacked:
                enemy.counter = enemy.turncount
                for i in range(leap):
                    option = random.randint(0, 9)
                    # 简化方向判断,也可以用字典映射优化(见下文)
                    if option == 1:
                        goingTo = (key[0]+1, key[1])
                    elif option == 2:
                        goingTo = (key[0]+1, key[1]+1)
                    elif option == 8:
                        goingTo = (key[0]-1, key[1]-1)
                    else:
                        goingTo = key
                    
                    # 处理地图方块逻辑
                    if self.getMapSquare(goingTo[1], goingTo[0]) == '#':
                        self.genSquare(goingTo[1], goingTo[0])
                    
                    # 执行移动:删除旧位置,添加新位置
                    del self.enemydict[key]
                    self.enemydict[goingTo] = enemy
                    
                    # 更新key为新位置,确保下一次leap从当前位置移动
                    key = goingTo

额外优化:用字典映射简化方向判断

你当前的多个elif方向判断可以用字典替代,让代码更简洁易维护:

# 在函数内或者类的其他位置定义方向映射
direction_offsets = {
    1: (1, 0),    # 右
    2: (1, 1),    # 右下
    # 补充其他方向的偏移量...
    8: (-1, -1),  # 左上
}

# 生成方向时替换多个elif
dx, dy = direction_offsets.get(option, (0, 0))  # 默认原地不动
goingTo = (key[0] + dx, key[1] + dy)

这样修改后,不仅解决了遍历的RuntimeError问题,还优化了代码的可读性和健壮性。

内容的提问来源于stack exchange,提问作者beef-stu

火山引擎 最新活动