Python递归遍历字典出现IndexError: list index out of range问题求助
递归遍历字典时的IndexError错误分析与解决
问题描述
你编写了一段遍历字典并判断值是否存在于字典键中的Python代码,执行时在if king_attack_moves[current][i] in king_attack_keys:处抛出IndexError: list index out of range错误。具体表现为处理{(450, 750): [(750, 450)]}时,变量i变为1,但该列表仅包含索引0的元素,你困惑于i为何会变成1。使用环境为Python 3.10.5和PyCharm 2020。
原代码
king_attack_moves = {(450, 750): [(750, 450)], (150, 450): [(450, 750)], (550, 50): [(150, 450), (50, 550)]} king_attack_keys = [(450, 750), (150, 450), (550, 50)] def standartization_for_king(current, king_keys, king_moves): if current in king_keys: for i in range(len(king_moves[current])): print(current,i,len(king_moves[current])) if king_moves[current][i] in king_attack_keys: current, king_moves = standartization_for_king(king_moves[current][i], king_keys,king_moves) return current, king_moves current, king_attack_moves = standartization_for_king((550, 50), king_attack_keys, king_attack_moves)
错误原因
核心问题是递归过程中修改了循环依赖的current变量,导致后续循环迭代使用错误的current值,具体执行流程如下:
- 初始调用时
current=(550,50),king_moves[current]的长度为2,因此循环i会取0和1。 - 当
i=0时,king_moves[current][i]=(150,450)在king_attack_keys中,触发递归调用。 - 递归层层深入后,最终返回时
current被修改为(450,750)。 - 回到初始循环的
i=1迭代时,current已经是(450,750),而king_moves[(450,750)]的长度仅为1,i=1超出了列表的索引范围,因此抛出IndexError。
简单来说,循环的range是基于初始current的长度生成的,但中途current被修改,后续迭代用新的current去匹配旧的索引范围,自然会越界。
解决方案
不要在循环迭代过程中修改current变量,改用临时变量处理递归结果,或者提前固定要遍历的列表内容,避免current变化影响遍历逻辑。
方案1:遍历列表元素而非索引,避免修改循环依赖的current
king_attack_moves = {(450, 750): [(750, 450)], (150, 450): [(450, 750)], (550, 50): [(150, 450), (50, 550)]} king_attack_keys = [(450, 750), (150, 450), (550, 50)] def standartization_for_king(current, king_keys, king_moves): if current in king_keys: # 直接遍历当前current对应的移动列表,不修改current本身 for move in king_moves[current]: print(current, move, len(king_moves[current])) if move in king_attack_keys: # 用临时变量接收递归返回结果,不覆盖原current _, king_moves = standartization_for_king(move, king_keys, king_moves) return current, king_moves current, king_attack_moves = standartization_for_king((550, 50), king_attack_keys, king_attack_moves)
方案2:提前固定遍历的列表,避免current修改影响遍历
如果需要保留索引遍历的逻辑,可以提前复制当前current对应的列表,确保遍历过程不受current变化影响:
king_attack_moves = {(450, 750): [(750, 450)], (150, 450): [(450, 750)], (550, 50): [(150, 450), (50, 550)]} king_attack_keys = [(450, 750), (150, 450), (550, 50)] def standartization_for_king(current, king_keys, king_moves): if current in king_keys: # 提前复制当前current对应的移动列表,固定遍历内容 current_moves = king_moves[current].copy() for i in range(len(current_moves)): print(current, i, len(current_moves)) if current_moves[i] in king_attack_keys: # 用临时变量接收递归返回的current,不覆盖原循环依赖的current temp_current, king_moves = standartization_for_king(current_moves[i], king_keys, king_moves) # 若业务需要更新current,可在此处根据逻辑调整,但不会影响当前循环 return current, king_moves current, king_attack_moves = standartization_for_king((550, 50), king_attack_keys, king_attack_moves)
内容的提问来源于stack exchange,提问作者HaterOfCaptcha
相关产品推荐
相关产品推荐

