Pythonのfor文とは、リストや文字列などの要素を先頭から1つずつ取り出して同じ処理を繰り返す構文で、range() は「0, 1, 2, …」のような連番をfor文に渡すための組み込みの型です。 for i in range(5): と書くと、i に 0 から 4 までが順に入り、処理が5回繰り返されます。

この記事では、range(n)・range(a, b)・range(a, b, step) の3つの形、逆順、1始まり、N回繰り返しを「書き方→出力」の早見表にまとめ、そのあとでインデックス付きループ(enumerate)、複数リストの同時ループ(zip)、つまずきやすい点を順に解説します。コードと出力はすべて Python 3.14.7 で実際に動かした結果で、小数の step を渡したときの TypeError、stop を含まないことによる1ずれ、ループ中にリストを変更したときの挙動も、エラー文や出力をそのまま載せています。

for文とrangeの早見表

rangeの書き方と出力

list(range(...)) で中身を表示した結果です。

やりたいこと 書き方 出力(list() で表示)
0からn-1まで(n回) range(5) [0, 1, 2, 3, 4]
aからb-1まで range(2, 6) [2, 3, 4, 5]
1始まりでnまで range(1, 6) [1, 2, 3, 4, 5]
2つおき(偶数) range(0, 10, 2) [0, 2, 4, 6, 8]
2つおき(奇数) range(1, 10, 2) [1, 3, 5, 7, 9]
5の倍数 range(5, 26, 5) [5, 10, 15, 20, 25]
逆順(n-1から0まで) range(4, -1, -1) [4, 3, 2, 1, 0]
逆順(reversedを使う) reversed(range(5)) [4, 3, 2, 1, 0]
逆順(nから1まで) range(5, 0, -1) [5, 4, 3, 2, 1]
逆順で2つおき range(10, 0, -2) [10, 8, 6, 4, 2]
負の数から range(-3, 3) [-3, -2, -1, 0, 1, 2]
向きが合わない(空になる) range(5, 1) []
0回(空になる) range(0) []

どの形でも「stop の値そのものは含まれない」のが共通ルールです。range(1, 6) は 1〜5、range(4, -1, -1) は 4〜0 になります。

for文のよく使う形

次のリストを使った場合の書き方と、ループ変数に入る値です。

names = ["Aoki", "Baba", "Chiba"]
ages = [30, 25, 41]
やりたいこと 書き方 ループ変数に入る値
N回繰り返す for _ in range(3): [0, 1, 2](値は使わない)
要素を順に取り出す for name in names: ['Aoki', 'Baba', 'Chiba']
インデックス付き(0始まり) for i, name in enumerate(names): [(0, 'Aoki'), (1, 'Baba'), (2, 'Chiba')]
インデックス付き(1始まり) for i, name in enumerate(names, start=1): [(1, 'Aoki'), (2, 'Baba'), (3, 'Chiba')]
インデックスだけで回す for i in range(len(names)): [0, 1, 2]
2つのリストを同時に for name, age in zip(names, ages): [('Aoki', 30), ('Baba', 25), ('Chiba', 41)]
要素を逆順に for name in reversed(names): ['Chiba', 'Baba', 'Aoki']
インデックスを逆順に for i in range(len(names) - 1, -1, -1): [2, 1, 0]
インデックス付きで逆順に for i, name in reversed(list(enumerate(names))): [(2, 'Chiba'), (1, 'Baba'), (0, 'Aoki')]
文字列を1文字ずつ for ch in "abc": ['a', 'b', 'c']
辞書のキーと値 for k, v in {"a": 1, "b": 2}.items(): [('a', 1), ('b', 2)]

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Python for文とrangeの使い方|逆順・インデックス付き早見表」

for文の基本形

書き方とインデント

for文は次の形で書きます。行末のコロンと、繰り返したい処理の字下げ(インデント、半角スペース4つが一般的)がそろって1つのまとまりになります。

for 変数 in 繰り返す対象:
    繰り返したい処理
for i in range(3):
    print("繰り返し中:", i)
print("終了")          # 字下げしていない行は、ループのあとに1回だけ動く

実行結果:

繰り返し中: 0
繰り返し中: 1
繰り返し中: 2
終了

字下げされた行だけがループの中身です。print("終了") は字下げしていないので、3回の繰り返しが終わったあとに1回だけ出力されます。

「回数で回す」のか「要素で回す」のか

Pythonのfor文は、リストなどの要素を直接取り出すのが基本です。数を数えるための変数が必要なときに range() を使います。

fruits = ["りんご", "みかん", "ぶどう"]

# 要素をそのまま使うなら、リストを直接 for に渡す
for fruit in fruits:
    print(fruit)

# 回数や番号が必要なときに range を使う
for i in range(3):
    print(i, "回目")

実行結果:

りんご
みかん
ぶどう
0 回目
1 回目
2 回目
目的 選ぶ書き方
要素を順に処理したい for x in リスト:
決まった回数だけ繰り返したい for _ in range(n):
連番そのものを使いたい for i in range(a, b):
要素と番号の両方がほしい for i, x in enumerate(リスト):
複数のリストを並べて処理したい for x, y in zip(リスト1, リスト2):

rangeの3つの形

range(stop):0からstopの手前まで

for i in range(5):
    print(i, end=" ")
print()
print(len(range(5)))    # 繰り返す回数は stop と同じ

実行結果:

0 1 2 3 4 
5

range(n) は 0 から n-1 までの n 個です。n 回繰り返すという意味でも、インデックスが 0 から始まるリストと組み合わせるという意味でも、この形が一番よく使われます。

range(start, stop):startからstopの手前まで

for i in range(2, 6):
    print(i, end=" ")
print()
print(len(range(2, 6)))   # 個数は stop - start

実行結果:

2 3 4 5 
4

range(start, stop, step):step個おき

print(list(range(0, 10, 2)))    # 0 から 2 つおき
print(list(range(1, 10, 3)))    # 1 から 3 つおき
print(list(range(10, 0, -3)))   # 10 から 3 つずつ減らす
print(list(range(0, 10, 20)))   # step が大きくても最初の1個は入る

実行結果:

[0, 2, 4, 6, 8]
[1, 4, 7]
[10, 7, 4, 1]
[0]

step を指定するときは、start も書く必要があります。range(10, 2) は「10 から 2 の手前まで」と解釈されるので、空になります。

今回、公式ドキュメント(Python 3.14 の「組み込み型」の range の項)を開いて確認したところ、中身は次の式で決まると書かれていました。

step i 番目の値 含まれる条件
正 start + step * i 値が stop より小さい
負 start + step * i 値が stop より大きい

あわせて、引数は整数であること、step を省略すると 1、start を省略すると 0 になること、step が 0 のときは ValueError になることも書かれています。

1始まりにする・N回繰り返す

n = 5

# 1 から n まで(n を含めたいので stop は n + 1)
for i in range(1, n + 1):
    print(i, end=" ")
print()

# N回繰り返すだけで、番号は使わない
for _ in range(3):
    print("こんにちは")

実行結果:

1 2 3 4 5 
こんにちは
こんにちは
こんにちは

1からnまでを含めたいときは range(1, n + 1) と書きます。番号を使わないループでは、変数名を _(アンダースコア)にしておくと「この値は使っていません」という意図が読む人に伝わります。

逆順で回す:range(n-1, -1, -1)とreversed(range(n))

2つの書き方を並べて比較

0 から n-1 までを逆順にたどる方法は2つあります。

n = 5

print(list(range(n - 1, -1, -1)))   # start=4, stop=-1, step=-1
print(list(reversed(range(n))))     # range(n) を逆からたどる
print(list(range(n - 1, -1, -1)) == list(reversed(range(n))))

実行結果:

[4, 3, 2, 1, 0]
[4, 3, 2, 1, 0]
True
比べる点 range(n - 1, -1, -1) reversed(range(n))
結果 n-1 から 0 まで n-1 から 0 まで(同じ)
読みやすさ 3つの数字を読み解く必要がある 「range(n) の逆」と一目でわかる
起きやすい書き間違い stop を 0 にして 0 が抜ける ほぼない
逆順で2つおきなどの調整 step を変えるだけ 元の range 側で調整する
向いている場面 開始・終了・間隔を細かく決めたい 単に逆順にしたい

単に逆順にするだけなら reversed(range(n)) のほうが書き間違いが起きにくく、stop に -1 を書く理由を考える必要もありません。

stopを0にすると0が抜ける

逆順でよくあるのが、stop に 0 を書いて最後の 0 が出力されないケースです。stop は含まれないので、0 まで出したいなら stop は -1 にします。

print(list(range(4, 0, -1)))    # 0 が含まれない
print(list(range(4, -1, -1)))   # 0 まで含まれる
print(list(range(0, 5, -1)))    # 向きが逆なので空になる

実行結果:

[4, 3, 2, 1]
[4, 3, 2, 1, 0]
[]

カウントダウンとリストの逆順

# 3 から 1 までのカウントダウン
for i in range(3, 0, -1):
    print(i)
print("スタート")

# リストの要素を逆順に取り出すなら、range を使わず reversed に渡す
tasks = ["設計", "実装", "テスト"]
for task in reversed(tasks):
    print(task)

実行結果:

3
2
1
スタート
テスト
実装
設計

インデックス付きで逆順に回す

tasks = ["設計", "実装", "テスト"]

# 方法1:インデックスを逆順に作る
for i in reversed(range(len(tasks))):
    print(i, tasks[i])

# 方法2:enumerate の結果をリストにしてから逆順にする
for i, task in reversed(list(enumerate(tasks))):
    print(i, task)

実行結果:

2 テスト
1 実装
0 設計
2 テスト
1 実装
0 設計

enumerate() の結果はそのままでは reversed() に渡せないので、いったん list() でリストにします。次のように直接渡すと TypeError になります。

tasks = ["設計", "実装", "テスト"]
try:
    for i, task in reversed(enumerate(tasks)):
        print(i, task)
except TypeError as e:
    print("TypeError:", e)

実行結果:

TypeError: 'enumerate' object is not reversible

インデックス付きループ:range(len())とenumerateの書き比べ

同じ処理を2通りで書く

「何番目か」と「要素」の両方を使いたいときの書き方を比べます。

names = ["Aoki", "Baba", "Chiba"]

print("--- range(len()) ---")
for i in range(len(names)):
    print(i, names[i])

print("--- enumerate ---")
for i, name in enumerate(names):
    print(i, name)

print("--- enumerate(start=1) ---")
for no, name in enumerate(names, start=1):
    print(f"{no}人目: {name}")

実行結果:

--- range(len()) ---
0 Aoki
1 Baba
2 Chiba
--- enumerate ---
0 Aoki
1 Baba
2 Chiba
--- enumerate(start=1) ---
1人目: Aoki
2人目: Baba
3人目: Chiba

enumerate() は、(番号, 要素) の組を順に返す組み込み関数です。公式ドキュメントの enumerate の項でも、start(既定値 0)からのカウントと、要素を含むタプルを返すと説明されています。

比べる点 range(len(x)) enumerate(x)
要素の取り出し x[i] と書く必要がある 変数にそのまま入る
1始まりにする i + 1 を自分で書く start=1 を指定する
使える対象 len() と添字が使えるもの for で回せるものなら何でも(ファイルの行など)
要素を書き換える x[i] = ... と書ける x[i] = ... と書ける(i を使う)
隣の要素を見る x[i + 1] と書きやすい 同じく i を使えば書ける

番号と要素の両方を使うなら enumerate が第一候補です。start=1 は表示用の番号を 1 から振るだけで、要素を飛ばすわけではありません。

startを指定したときにインデックスとして使うとずれる

enumerate(x, start=1) の番号を、そのまま x[番号] に使うと位置が1つずれます。番号は表示用、インデックスは 0 始まりと分けて考えると混乱しません。

names = ["Aoki", "Baba", "Chiba"]

try:
    for no, name in enumerate(names, start=1):
        print(no, name, names[no])   # no は 1 始まりなので、1つ後ろを指す
except IndexError as e:
    print("IndexError:", e)

実行結果:

1 Aoki Baba
2 Baba Chiba
IndexError: list index out of range

range(len())が向いている場面

インデックスそのものが主役になる処理では、range(len()) が素直に書けます。

prices = [100, 250, 80, 300]

# 1) 隣どうしを比べる(最後の要素には「次」がないので len - 1 まで)
for i in range(len(prices) - 1):
    print(prices[i], "→", prices[i + 1], "差", prices[i + 1] - prices[i])

# 2) 1つおきに処理する
for i in range(0, len(prices), 2):
    print(i, prices[i])

# 3) リストの中身を書き換える
for i in range(len(prices)):
    prices[i] = prices[i] * 2
print(prices)

実行結果:

100 → 250 差 150
250 → 80 差 -170
80 → 300 差 220
0 100
2 80
[200, 500, 160, 600]

ループ変数に代入しても元のリストは変わらない

for文で取り出した変数に値を代入しても、リストの中身は変わりません。書き換えたいときはインデックスを使うか、新しいリストを作ります。

prices = [100, 250, 80]

for p in prices:
    p = p * 2            # 変数 p が別の値を指すだけ
print(prices)            # 変わっていない

for i, p in enumerate(prices):
    prices[i] = p * 2    # インデックスで代入する
print(prices)

doubled = [p * 2 for p in prices]   # 新しいリストを作る(内包表記)
print(doubled)

実行結果:

[100, 250, 80]
[200, 500, 160]
[400, 1000, 320]

zipで複数のリストを同時にループする

基本の使い方

zip() は、複数のリストから同じ位置の要素を1つずつ組にして返します。

names = ["Aoki", "Baba", "Chiba"]
ages = [30, 25, 41]
teams = ["A", "B", "A"]

for name, age in zip(names, ages):
    print(name, age)

# 3つ以上でも同じ書き方、enumerate と組み合わせて番号も付けられる
for no, (name, age, team) in enumerate(zip(names, ages, teams), start=1):
    print(no, name, age, team)

実行結果:

Aoki 30
Baba 25
Chiba 41
1 Aoki 30 A
2 Baba 25 B
3 Chiba 41 A

enumerate と zip を組み合わせるときは、zip 側の変数を丸かっこでまとめます。

range(len())で書いた場合との比較

names = ["Aoki", "Baba", "Chiba"]
ages = [30, 25, 41]

# range(len()) 版:添字が2か所に出てくる
for i in range(len(names)):
    print(names[i], ages[i])

# zip 版:添字が要らない
for name, age in zip(names, ages):
    print(name, age)

実行結果:

Aoki 30
Baba 25
Chiba 41
Aoki 30
Baba 25
Chiba 41

長さが違うときは短いほうで止まる

names = ["Aoki", "Baba", "Chiba"]
ages = [30, 25]              # 1件少ない

print(list(zip(names, ages)))        # 短いほうに合わせて止まる

try:
    print(list(zip(names, ages, strict=True)))   # 長さが違えば例外にする
except ValueError as e:
    print("ValueError:", e)

実行結果:

[('Aoki', 30), ('Baba', 25)]
ValueError: zip() argument 2 is shorter than argument 1

既定では短いほうに合わせて静かに止まります。 長さがそろっているはずのデータなら、strict=True(Python 3.10 以降)を付けると、ずれに早く気づけます。長いほうに合わせたいときは itertools.zip_longest() を使います。

小数のstepはTypeErrorになる

エラーを再現する

range() に渡せるのは整数だけです。小数を渡すと TypeError になります。

for x in range(0, 1, 0.1):
    print(x)

実行結果:

Traceback (most recent call last):
  File "sample.py", line 1, in <module>
    for x in range(0, 1, 0.1):
             ~~~~~^^^^^^^^^^^
TypeError: 'float' object cannot be interpreted as an integer

start や stop に小数を渡した場合も同じです。

for args in [(0.5, 3), (0, 2.0), (5 / 1,)]:
    try:
        range(*args)
    except TypeError as e:
        print(args, "→ TypeError:", e)

実行結果:

(0.5, 3) → TypeError: 'float' object cannot be interpreted as an integer
(0, 2.0) → TypeError: 'float' object cannot be interpreted as an integer
(5.0,) → TypeError: 'float' object cannot be interpreted as an integer

5 / 1 のように割り切れる計算でも、/ の結果は float(5.0)になるため同じエラーになります。整数の割り算には // を使います。

小数きざみで回したいときの書き方

整数の range で回して、ループの中で割り算するのが、誤差を小さく保てる書き方です。

# 0.0 から 0.9 まで 0.1 きざみ
for i in range(10):
    x = i / 10
    print(x, end=" ")
print()

# 1.0 から 2.0 まで 0.25 きざみ(両端を含む)
start, stop, step = 1.0, 2.0, 0.25
count = round((stop - start) / step) + 1
print([start + step * i for i in range(count)])

実行結果:

0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 
[1.0, 1.25, 1.5, 1.75, 2.0]

比較のために、0.1 を足し続ける書き方も動かしてみます。

x = 0.0
values = []
while x < 1.0:
    values.append(x)
    x += 0.1          # 足し算を重ねるたびに、わずかな誤差が積み重なる
print(values)
print(len(values))    # 10個のつもりが11個になる

実行結果:

[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999]
11

0.1 は2進数では正確に表せない値なので、足し算を重ねると誤差がたまり、回数まで変わることがあります。回数は整数で管理し、値はそのつど計算すると、この影響を受けません。

やりたいこと 書き方
0.1 きざみで 10 回 for i in range(10): x = i / 10
0.5 きざみ for i in range(n): x = i * 0.5
区間を n 等分 for i in range(n + 1): x = a + (b - a) * i / n
厳密な10進数で計算 decimal.Decimal を使い、Decimal("0.1") * i とする

stopを含まないことによる1ずれ

stop の値が含まれないことを忘れると、繰り返しが1回少ない、または最後の要素に届かないという結果になります。エラーにはならないので、出力を見て気づくことが多い箇所です。

1からnまでの合計

n = 10

total = 0
for i in range(1, n):        # 1〜9 になっている
    total += i
print(total)

total = 0
for i in range(1, n + 1):    # 1〜10
    total += i
print(total)

print(sum(range(1, n + 1)))  # sum に range を渡しても同じ

実行結果:

45
55
55

よくある1ずれの一覧

次のリストを例にします(a = [10, 20, 30, 40]、長さ 4)。

書き方 実際に入る値 起きること 直し方
range(1, 10) [1, 2, 3, 4, 5, 6, 7, 8, 9] 10 が含まれない range(1, 11)
range(1, len(a)) [1, 2, 3] 先頭(0番目)を処理しない range(len(a))
range(len(a) + 1) [0, 1, 2, 3, 4] a[4] で IndexError range(len(a))
range(len(a) - 1) [0, 1, 2] 最後の要素を処理しない 隣を見る処理以外は range(len(a))
range(4, 0, -1) [4, 3, 2, 1] 0 が含まれず、a[4] で IndexError range(3, -1, -1)
a = [10, 20, 30, 40]

try:
    for i in range(len(a) + 1):
        print(i, a[i])
except IndexError as e:
    print("IndexError:", e)

実行結果:

0 10
1 20
2 30
3 40
IndexError: list index out of range

迷ったら list(range(...)) を1回 print して、最初と最後の値を確かめるのが確実です。

ループが終わったあとの変数の値

for文の変数は、ループが終わっても最後に入った値のまま残ります。「最後は stop の値になっている」と考えると1ずれます。

for i in range(5):
    pass
print(i)        # 5 ではなく 4

for j in range(0):
    pass
try:
    print(j)    # 1回も回らなければ、変数は作られない
except NameError as e:
    print("NameError:", e)

実行結果:

4
NameError: name 'j' is not defined

ループの中でiを変えても、次の周回には影響しない

for i in range(5):
    print(i, end=" ")
    i += 2          # 次の周回で i は range から取り出した値に戻る
print()

# 飛ばしながら進めたいときは step を使う
for i in range(0, 5, 2):
    print(i, end=" ")
print()

実行結果:

0 1 2 3 4 
0 2 4 

for文は毎回 range から次の値を取り出して i に入れ直すので、ループの中で i を増やしても飛ばすことはできません。間隔を変えたいときは step を使い、条件によって進み方を変えたいときは while 文が合っています。

ループ中にリストを変更したときの挙動

回しているリストから要素を削除すると、要素が飛ばされる

偶数をすべて取り除くつもりで、次のように書いたとします。

nums = [2, 4, 6, 7, 8]

for n in nums:
    if n % 2 == 0:
        nums.remove(n)

print(nums)    # 偶数が残っている

実行結果:

[4, 7]

エラーは出ませんが、4 と 8 が残りました。 for文は内部で「次は何番目を見るか」を数えています。要素を削除すると後ろの要素が前に詰まるので、詰まってきた要素を見ないまま次に進んでしまいます。

周回 見る位置 そのときのリスト 取り出す値 処理
1 0 [2, 4, 6, 7, 8] 2 削除 → [4, 6, 7, 8]
2 1 [4, 6, 7, 8] 6 削除 → [4, 7, 8](4 は見られない)
3 2 [4, 7, 8] 8 削除 → [4, 7](7 は見られない)
4 3 [4, 7] なし 終了

この表の流れは、次のコードで実際に確かめられます。

nums = [2, 4, 6, 7, 8]

for n in nums:
    print("取り出した値:", n, " リスト:", nums)
    if n % 2 == 0:
        nums.remove(n)

実行結果:

取り出した値: 2  リスト: [2, 4, 6, 7, 8]
取り出した値: 6  リスト: [4, 6, 7, 8]
取り出した値: 8  リスト: [4, 7, 8]

range(len())で回しながら削除するとIndexErrorになる

range(len(nums)) はループの開始時に回数が決まるため、途中でリストが短くなると、存在しない位置を見にいきます。

nums = [2, 4, 6, 7, 8]

try:
    for i in range(len(nums)):
        if nums[i] % 2 == 0:
            del nums[i]
except IndexError as e:
    print("IndexError:", e)
print(nums)

実行結果:

IndexError: list index out of range
[4, 7]

直し方は4通り

# 方法1:条件に合うものだけを集めた新しいリストを作る(おすすめ)
nums = [2, 4, 6, 7, 8]
nums = [n for n in nums if n % 2 != 0]
print(nums)

# 方法2:コピーを回して、元のリストから削除する
nums = [2, 4, 6, 7, 8]
for n in nums[:]:            # nums[:] はコピー
    if n % 2 == 0:
        nums.remove(n)
print(nums)

# 方法3:後ろから前へ、インデックスで削除する
nums = [2, 4, 6, 7, 8]
for i in reversed(range(len(nums))):
    if nums[i] % 2 == 0:
        del nums[i]
print(nums)

# 方法4:同じリストの中身を入れ替える(ほかの変数からも見えている場合)
nums = [2, 4, 6, 7, 8]
nums[:] = [n for n in nums if n % 2 != 0]
print(nums)

実行結果:

[7]
[7]
[7]
[7]
方法 特徴 向いている場面
内包表記で新しいリストを作る 短く、意図が伝わりやすい ほとんどの場面
コピーを回す 元の書き方を大きく変えずに済む 削除以外の処理も一緒に行うとき
後ろから削除する 削除しても、まだ見ていない前側の位置が変わらない インデックスを使う処理
nums[:] = ... 同じリストのまま中身を入れ替える 引数で受け取ったリストを書き換えるとき

後ろから回すと安全なのは、削除で位置が変わるのが「すでに見終わった後ろ側」だけだからです。逆順ループが役に立つ代表的な場面です。

ループ中に追加すると終わらなくなる・辞書は例外になる

回しているリストに要素を追加し続けると、いつまでも末尾に届かなくなります。次のコードは確認のために100件で打ち切っています。

nums = [1, 2, 3]
for n in nums:
    nums.append(n * 10)      # 回しているリスト自身に追加している
    if len(nums) >= 100:     # 確認用の打ち切り(これがないと終わらない)
        break
print(len(nums))

# 辞書は、ループ中に大きさが変わると例外で知らせてくれる
stock = {"ペン": 0, "ノート": 3, "付箋": 0}
try:
    for name in stock:
        if stock[name] == 0:
            del stock[name]
except RuntimeError as e:
    print("RuntimeError:", e)

# 直し方:キーの一覧をリストにしてから回す
stock = {"ペン": 0, "ノート": 3, "付箋": 0}
for name in list(stock):
    if stock[name] == 0:
        del stock[name]
print(stock)

実行結果:

100
RuntimeError: dictionary changed size during iteration
{'ノート': 3}

「回している対象そのものの長さを、ループの中で変えない」と決めておくと、ここで紹介した挙動には出会わずに済みます。

rangeの性質を知っておく

rangeはリストではなく、必要なときに値を計算する

range() が返すのは range 型のオブジェクトで、数字を全部並べたリストではありません。start・stop・step の3つだけを覚えておき、必要になったときに値を計算します。

import sys

r = range(1_000_000)
print(r)                              # 中身は表示されない
print(type(r))
print(sys.getsizeof(r))               # range のサイズ(バイト)
print(sys.getsizeof(list(r)))         # リストにした場合のサイズ(バイト)
print(sys.getsizeof(range(10**12)))   # 桁が増えてもサイズは同じ

実行結果:

range(0, 1000000)
<class 'range'>
48
8000056
48

公式ドキュメントでも、range はサイズや表す範囲にかかわらず、常に一定の小さなメモリしか使わない点が利点として挙げられています。中身を目で確認したいときだけ list() に渡す、という使い分けで十分です。

rangeで使える操作

r = range(0, 20, 2)

print(len(r))          # 個数
print(r[3], r[-1])     # インデックスで取り出す
print(r[2:5])          # スライスすると range が返る
print(10 in r, 11 in r)   # 含まれるかどうか
print(r.index(10))     # 何番目か
print(r.start, r.stop, r.step)
print(sum(r), min(r), max(r))
print(range(0, 3) == range(0, 3, 1))   # 中身が同じなら等しい

実行結果:

10
6 18
range(4, 10, 2)
True False
5
0 20 2
90 0 18
True
操作 書き方 補足
個数 len(r) ループが何回まわるかの確認に使える
n番目の値 r[n] 負の数で末尾からも取れる
含まれるか x in r 1つずつ調べずに計算で判定される
逆順 reversed(r)、r[::-1] どちらも使える
リストにする list(r) 中身を表示・保存したいとき
合計 sum(r) for文を書かずに合計できる

break・continue・elseと入れ子のループ

途中で抜ける・飛ばす

for i in range(1, 8):
    if i % 2 == 0:
        continue       # 偶数は飛ばして次の周回へ
    if i > 5:
        break          # 5 を超えたらループを抜ける
    print(i)

実行結果:

1
3
5

見つからなかったときの処理をelseで書く

for文には else を付けられます。break で抜けなかった場合だけ実行されるので、「探して見つからなかったとき」の処理に使えます。

def find_first_multiple(numbers, base):
    for n in numbers:
        if n % base == 0:
            print(base, "の倍数が見つかりました:", n)
            break
    else:
        print(base, "の倍数はありません")

find_first_multiple([3, 8, 10, 15], 5)
find_first_multiple([3, 8, 11], 5)

実行結果:

5 の倍数が見つかりました: 10
5 の倍数はありません

入れ子のループで表を作る

for i in range(1, 4):
    for j in range(1, 6):
        print(f"{i * j:3}", end="")
    print()          # 内側のループが終わるたびに改行

実行結果:

  1  2  3  4  5
  2  4  6  8 10
  3  6  9 12 15

外側の変数を i、内側を j のように別の名前にするのがポイントです。同じ名前にすると、内側のループが外側の値を上書きします。

そのまま使えるレシピ集

# 1) 1〜100 の合計と、偶数だけの合計
print(sum(range(1, 101)), sum(range(2, 101, 2)))

# 2) 3の倍数だけを集める
print([i for i in range(1, 20) if i % 3 == 0])

# 3) 2乗のリスト
print([i ** 2 for i in range(1, 6)])

# 4) リストを3件ずつに区切って処理する
items = ["A", "B", "C", "D", "E", "F", "G"]
for start in range(0, len(items), 3):
    print(start, items[start:start + 3])

# 5) 連番付きの名前を作る
print([f"file_{i:03}.txt" for i in range(1, 4)])

# 6) 同じ値で埋めたリスト、連番のリスト
print([0] * 5, list(range(5)))

# 7) 番号付きで一覧表示する
for no, item in enumerate(["議事録", "見積書", "手順書"], start=1):
    print(f"{no}. {item}")

実行結果:

5050 2550
[3, 6, 9, 12, 15, 18]
[1, 4, 9, 16, 25]
0 ['A', 'B', 'C']
3 ['D', 'E', 'F']
6 ['G']
['file_001.txt', 'file_002.txt', 'file_003.txt']
[0, 0, 0, 0, 0] [0, 1, 2, 3, 4]
1. 議事録
2. 見積書
3. 手順書

よくあるエラーと直し方

エラー文(Python 3.14.7 での出力) 起きる書き方 直し方
TypeError: 'int' object is not iterable for i in 5: for i in range(5):
TypeError: 'float' object cannot be interpreted as an integer range(0, 1, 0.1)、range(n / 2) 整数で回して中で割る、// を使う
TypeError: 'list' object cannot be interpreted as an integer range(a)(a はリスト) range(len(a))
TypeError: 'str' object cannot be interpreted as an integer range(input()) range(int(input()))
ValueError: range() arg 3 must not be zero range(0, 10, 0) step は 0 以外にする
TypeError: range expected at most 3 arguments, got 4 引数が4つ以上 start・stop・step の3つまで
IndexError: list index out of range range(len(a) + 1) で a[i] range(len(a))
TypeError: 'enumerate' object is not reversible reversed(enumerate(x)) reversed(list(enumerate(x)))

コロンの書き忘れや字下げの不足は、実行前の文法チェックで知らせてくれます。

for i in range(3)
    print(i)

実行結果:

  File "colon.py", line 1
    for i in range(3)
                     ^
SyntaxError: expected ':'
for i in range(3):
print(i)

実行結果:

  File "indent.py", line 2
    print(i)
    ^^^^^
IndentationError: expected an indented block after 'for' statement on line 1

エラー文には行番号と、足りないものの説明が含まれています。まず最後の1行(エラーの種類と説明)を読み、次に行番号の場所を確認すると、直す箇所が早く見つかります。

書き方を選ぶ判断表

状況 選ぶ書き方 理由
要素だけを使う for x in a: 添字が要らず、読みやすい
回数だけ決まっている for _ in range(n): 値を使わないことが伝わる
番号と要素を使う for i, x in enumerate(a): a[i] を書かずに済む
表示用に1から番号を振る enumerate(a, start=1) i + 1 の書き忘れが起きない
2つのリストを並べる zip(a, b) 添字を2か所に書かずに済む
単に逆順にする reversed(a)、reversed(range(n)) stop の計算が要らない
開始・終了・間隔を細かく指定 range(start, stop, step) 3つの数字で制御できる
隣の要素と比べる range(len(a) - 1) または zip(a, a[1:]) 最後の要素の「次」を見にいかない
要素を削除しながら回す 内包表記で新しいリストを作る 回している対象の長さを変えない
小数きざみで回す 整数の range + 割り算 誤差がたまらない

よくある質問

Q. range(5) はなぜ 5 を含まないのですか? A. range は「start から始めて stop の手前まで」と決められているためです。この決まりのおかげで、range(n) はちょうど n 回の繰り返しになり、長さ n のリストのインデックス(0〜n-1)ともそのまま一致します。range(a, b) の個数が b - a で計算できるという利点もあります。n を含めたいときは range(1, n + 1) と書きます。

Q. 逆順は range(n-1, -1, -1) と reversed(range(n)) のどちらがよいですか? A. 結果は同じなので、単に逆順にしたいだけなら読みやすい reversed(range(n)) をおすすめします。「10 から 2 つずつ減らす」のように開始・終了・間隔を細かく決めたいときは、range(10, 0, -2) のように3つの引数で書くほうが向いています。リストの要素を逆順に取り出すだけなら、reversed(リスト) で range 自体が要りません。

Q. range(len(list)) は使わないほうがよいのですか? A. 使ってかまいません。要素と番号の両方を使うだけなら enumerate のほうが短く書けますが、隣の要素と比べる・1つおきに処理する・後ろから削除するなど、インデックスそのものが主役の処理では range(len()) が素直な書き方です。目的に合うほうを選べば問題ありません。

Q. 0.1 きざみでループするにはどうすればよいですか? A. range には整数しか渡せないので、for i in range(10): x = i / 10 のように整数で回して、ループの中で割り算します。0.1 を足し続ける書き方は誤差がたまり、回数が変わることがあります。厳密な10進数の計算が必要なら、標準ライブラリの decimal.Decimal を使います。

まとめ

  • for 変数 in 対象: が基本形。回数や連番が必要なときに range() を使う
  • range は range(stop)・range(start, stop)・range(start, stop, step) の3形。stop の値は含まれないので、1〜n は range(1, n + 1)
  • 逆順は reversed(range(n)) が読みやすく、細かく指定するなら range(n - 1, -1, -1)。stop を 0 にすると 0 が抜ける
  • 番号と要素の両方を使うなら enumerate、1始まりは start=1。複数のリストを並べるなら zip
  • range に渡せるのは整数だけ。小数きざみは整数で回して中で割る
  • 回しているリストの長さをループの中で変えない。削除したいときは内包表記で新しいリストを作るか、後ろから削除する
  • 迷ったら list(range(...)) を表示して、最初と最後の値を確かめる

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Python for文とrangeの使い方|逆順・インデックス付き早見表」

株式会社RJCでは、Pythonのfor文やrangeのような基礎文法を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?