Code Fix

上級

イテレート中のリスト変更で要素が飛ばされる

forループでリストを走査しながら同じリストからremove()すると、要素の位置がずれて一部が処理から漏れます。

なぜエラーが出ないのか

出力: [1, 2, 3]
(エラーなし)
Pythonは何も報告しません。文法として正しいためです
出力: [1, 2, 3]
実際の挙動 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  nums = [1, 2, 2, 3]
 2  for n in nums       :
                  ^
 3      if n == 2:
 4          nums.remove(n)
 5  print(nums)
出力: [1, 2, 3]期待: [1, 3] (エラーにはなりません)

リストを変更しながら同じリストをイテレートすると、要素がずれて一部が処理から漏れます。nums[:]でコピーを作ってからイテレートすれば元のリストを安全に変更できます。

直し方: numsnums[:] にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  fruits = ["apple", "banana", "banana", "cherry"]
 2  for f in fruits       :
                   ^
 3      if f == "banana":
 4          fruits.remove(f)
 5  print(fruits)
出力: ['apple', 'banana', 'cherry']期待: ['apple', 'cherry'] (エラーにはなりません)

同じ値が連続している場合に特に発覚しやすいパターンです。1つ消えると、残りの1つが繰り上がって判定をすり抜けます。

直し方: fruitsfruits[:] にします。

この問題を解いてみる →

パターン3

 1  scores = [0, 0, 5, 10]
 2  for s in scores       :
                   ^
 3      if s == 0:
 4          scores.remove(s)
 5  print(scores)
出力: [0, 5, 10]期待: [5, 10] (エラーにはなりません)

0点を除外するつもりが1つ残ってしまう典型例です。件数が多いデータほど発覚が遅れます。

直し方: scoresscores[:] にします。

この問題を解いてみる →

よくある誤解

例外は一切出ません。リストにはサイズ変化を検出する仕組みが無いため、静かに間違った結果になります。

まとめ

イテレート中のリスト変更で要素が飛ばされるは上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)