Code Fix

中級

range()の範囲指定でループが1回分ずれる

range()の終端は指定した値を含みません。全要素を回すつもりでrange(len(...) - 1)のように書くと、最後の1つが抜け落ちます。

なぜエラーが出ないのか

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

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

パターン1

 1  nums = [1, 2, 3, 4, 5]
 2  total = 0
 3  for i in range(4            ):
                         ^
 4      total += nums[i]
 5  print(total)
出力: 10期待: 15 (エラーにはなりません)

range(4)は0から3までの4個しか作りません。5個の要素をすべて合計したい場合はrange(5)、あるいはrange(len(nums))にします。

直し方: 4 を 5 にします。

この問題を解いてみる →

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

パターン2

 1  count = 0
 2  for i in range(1, 5 ):
                       ^
 3      count += 1
 4  print(count)
出力: 4期待: 5 (エラーにはなりません)

range(1, 5)は1,2,3,4の4個までです。5まで含めたい場合は終端を1つ増やしてrange(1, 6)にします。

直し方: 5 を 6 にします。

この問題を解いてみる →

パターン3

 1  days = ["Mon", "Tue", "Wed", "Thu", "Fri"]
 2  for i in range(len(days) - 1):
                         ^
 3      print(days[i])
出力: Mon Tue Wed Thu期待: Mon〜Friの5行 (エラーにはなりません)

range(len(days) - 1)は最後の要素の1つ手前で止まります。全要素を回すにはrange(len(days))にします。

直し方: len(days) - 1 を len(days) にします。

この問題を解いてみる →

パターン4

 1  nums = [10, 20, 30]
 2  total = 0
 3  for i in range(1 , len(nums)):
                    ^
 4      total += nums[i]
 5  print(total)
出力: 50期待: 60 (エラーにはなりません)

開始位置を1からにすると、先頭の要素が合計から抜け落ちます。全要素を対象にするには0から始めます。

直し方: 1 を 0 にします。

この問題を解いてみる →

パターン5

 1  nums = [1, 2, 3, 4, 5, 6]
 2  total = 0
 3  for i in range(0, len(nums), 3):
                                 ^
 4      total += nums[i]
 5  print(total)
出力: 5期待: 21 (エラーにはなりません)

range()の3つ目の引数は増分(ステップ)です。1のつもりで大きい値を書くと、要素を飛ばして合計してしまいます。

直し方: 3 を 1 にします。

この問題を解いてみる →

よくある誤解

「要素数と同じ数値を書けば全部回る」と思いがちですが、range(n)はn回(0からn-1まで)繰り返すという定義です。境界の扱いを勘違いすると1回分ずれます。

実務での勘所

range()の終端を含まない設計は、単独のルールではなくPython全体で一貫した規約です。リストのスライスs[0:n]も同じく終端nを含みません。この一貫性のおかげで、len(items)が返す要素数をそのままrange(len(items))やitems[0:len(items)]の終端に使えば、常に過不足なく全要素を指せます。他の言語や日常の感覚にある「1から10まで」のような両端を含む数え方に慣れていると、この半開区間という考え方への切り替えに時間がかかることがあります。

演習をはじめる

関連するエラー

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