Python for循环迭代添加元素行为不一致问题咨询
Python for循环迭代时修改列表的行为差异与保龄球计分问题解决
一、两种不同的循环表现
1. 能检测到新增元素的循环示例
当直接在迭代的原列表上添加元素时,for循环会继续遍历新增的元素:
array = [6,7] for i, n in enumerate(array): print(array) if i == 1: array.append(1)
2. 无法检测新增元素的保龄球计分代码
在下面的保龄球计分函数中,虽然在循环内给frames添加了新元素,但循环并未继续执行新增元素的遍历:
def bowling_score(frames): score = 0 frames = frames.split(" ") multipliers = [1,1,1,1] roll = 0 for i, frame in enumerate(frames): print(i) if "X" in frame: score += 10 * multipliers[roll] multipliers[roll+1] += 1 if i < 9 else 0 multipliers[roll+2] += 1 if i < 9 else 0 if i >= 9 and len(frame) > 1: frames = frames + [frame[1:]] print(frames) elif "/" in frame: score += int(frame[0]) * multipliers[roll] score += (10-int(frame[0])) * multipliers[roll+1] multipliers[roll+2] += 1 if i < 9 else 0 if i >= 9 and len(frame) > 1: frames = frames + [frame[2:]] else: score += int(frame[0]) * multipliers[roll] print(f"len of frame = {len(frame)}") score += int(frame[1]) * multipliers[roll+1] roll += len(frame) multipliers = multipliers + [1]*len(frame) return score print(bowling_score('X X X X X X X X X XXX'))
二、未解决问题的ChatGPT回答
该行为在Python官方文档中并未明确说明,考虑到Python通常允许迭代时修改列表,这确实令人意外。这可能与Python for循环实现中的某些特定优化有关。尽管如此,建议仍然不变:通常最好避免在迭代列表时修改它,因为行为可能出乎意料且不直观。
要在你的bowling_score函数中处理此问题,可以使用没有这种边缘情况的其他类型循环,例如while循环。
三、问题解析与解决方案
为何出现行为差异?
Python的for循环依赖迭代器工作,迭代器在循环启动时就绑定到了初始的列表对象上:
- 第一个示例中,
array.append(1)是直接修改原列表对象,迭代器会在每次迭代时读取列表的当前状态,因此能遍历到新增元素。 - 第二个示例中,
frames = frames + [frame[1:]]是创建了一个新的列表对象,并让变量frames指向这个新列表,但循环的迭代器仍然绑定在最初的那个列表上,完全不会感知到新列表的存在,自然不会遍历新添加的元素。
保龄球计分问题的正确解决方法
有两种可靠的解决思路:
思路1:修改原列表而非创建新列表
把创建新列表的代码替换为直接在原列表上追加元素,即用frames.append(...)替代frames = frames + [...]:
修改后的关键代码片段:
# 替换X分支的frames赋值 if i >= 9 and len(frame) > 1: frames.append(frame[1:]) print(frames) # 替换/分支的frames赋值 if i >= 9 and len(frame) > 1: frames.append(frame[2:])
思路2:改用while循环手动控制遍历
如果需要更灵活的遍历控制,改用while循环,手动维护索引,这样完全不受列表对象变更的影响:
def bowling_score(frames): score = 0 frames = frames.split(" ") multipliers = [1,1,1,1] roll = 0 i = 0 while i < len(frames): frame = frames[i] print(i) if "X" in frame: score += 10 * multipliers[roll] multipliers[roll+1] += 1 if i < 9 else 0 multipliers[roll+2] += 1 if i < 9 else 0 if i >= 9 and len(frame) > 1: frames.append(frame[1:]) print(frames) elif "/" in frame: score += int(frame[0]) * multipliers[roll] score += (10-int(frame[0])) * multipliers[roll+1] multipliers[roll+2] += 1 if i < 9 else 0 if i >= 9 and len(frame) > 1: frames.append(frame[2:]) else: score += int(frame[0]) * multipliers[roll] print(f"len of frame = {len(frame)}") score += int(frame[1]) * multipliers[roll+1] roll += len(frame) multipliers = multipliers + [1]*len(frame) i += 1 return score print(bowling_score('X X X X X X X X X XXX'))
内容的提问来源于stack exchange,提问作者calvinusesyourcode
相关产品推荐
相关产品推荐

