タイトル: range(連続した整数を生成する)
SEOタイトル: Python range の全パターン(start / stop / step、list 化、enumerate、遅延評価)
| この記事の要点 |
|
range の 3 つの引数パターン
# ① 引数 1 つ: 0 から stop 未満
list(range(5)) # [0, 1, 2, 3, 4]
# ② 引数 2 つ: start から stop 未満
list(range(2, 7)) # [2, 3, 4, 5, 6]
# ③ 引数 3 つ: step 刻み
list(range(0, 10, 2)) # [0, 2, 4, 6, 8]
list(range(10, 0, -1)) # [10, 9, 8, ..., 1]
list(range(0, -10, -2)) # [0, -2, -4, -6, -8]
# step=0 はエラー
range(0, 5, 0) # ValueError: range() arg 3 must not be zero
典型的な使い方
# ① for ループの回数指定
for i in range(10):
print(i) # 0..9
# ② インデックス付きアクセス(enumerate の方が Pythonic)
items = ['a', 'b', 'c']
for i in range(len(items)):
print(i, items[i])
# ③ より Python らしく
for i, x in enumerate(items):
print(i, x)
# ④ 範囲指定の逆順
for i in range(len(items) - 1, -1, -1):
print(items[i])
# あるいは
for x in reversed(items):
print(x)
# ⑤ ジャンプしながら
for i in range(0, 100, 10):
print(i) # 0, 10, 20, ..., 90
range は Lazy(遅延評価オブジェクト)
Python 3 では range はその場でリストを作らず、必要な値を都度計算する遅延オブジェクトです。メモリ効率が良く、range(10**18) でも瞬時に作れます:
r = range(10)
print(type(r)) #
print(r) # range(0, 10)
print(list(r)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 巨大 range でも OK(実体化しない)
big = range(10 ** 18)
print(big[500]) # 500 — インデックスアクセス O(1)
print(len(big)) # 1000000000000000000 — O(1)
print(7 in big) # True — 含有判定も O(1)
# でも list 化すると死ぬ
# list(big) # MemoryError
range オブジェクトの操作
| 操作 | 結果 | 計算量 |
|---|---|---|
len(r) | 要素数 | O(1) |
r[i] | i 番目の値 | O(1) |
r[i:j] | 新 range | O(1) |
x in r | 含有判定 | O(1)(数値の場合) |
list(r) | リスト化 | O(n) ★メモリ注意 |
reversed(r) | 逆順 iterator | O(1) |
list(range()) でリスト化
nums = list(range(1, 11))
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 内包表記と組み合わせて
squares = [i ** 2 for i in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# zip / dict 化
keys = ['a', 'b', 'c']
d = dict(zip(keys, range(len(keys))))
# {'a': 0, 'b': 1, 'c': 2}
enumerate と range の使い分け
items = ['apple', 'banana', 'cherry']
# ❌ C 言語スタイル(非 Pythonic)
for i in range(len(items)):
print(i, items[i])
# ✅ Pythonic
for i, item in enumerate(items):
print(i, item)
# 1 始まりにしたい
for i, item in enumerate(items, start=1):
print(i, item) # 1 apple, 2 banana, 3 cherry
# 複数リスト同時
names = ['Alice', 'Bob']
ages = [30, 25]
for i, (n, a) in enumerate(zip(names, ages)):
print(i, n, a)
Python 2 vs Python 3
| 項目 | Python 2 | Python 3 |
|---|---|---|
range() | list を返す | range オブジェクト(Lazy) |
xrange() | Lazy(Python 3 の range と同じ) | 削除 |
| メモリ | 巨大 range は危険 | O(1) で安全 |
| 含有判定 | O(n) リスト検索 | O(1) 算術 |
浮動小数の range が欲しい場合
range は整数専用です。浮動小数なら NumPy の arange / linspace を使います:
import numpy as np
# 0.0 から 1.0 まで 0.1 刻み
np.arange(0.0, 1.0, 0.1)
# [0.0, 0.1, 0.2, ..., 0.9]
# 0.0 から 1.0 を 11 等分
np.linspace(0.0, 1.0, 11)
# [0.0, 0.1, 0.2, ..., 1.0]
# 自作するなら
def frange(start, stop, step):
while start < stop:
yield start
start += step
list(frange(0, 1, 0.25))
# [0, 0.25, 0.5, 0.75]
FAQ
Q: stop を含めたい(1〜10)
A: range(1, 11) のように stop を +1 する。Python 由来の慣習で stop 非包含です。
Q: range を逆順にしたい
A: range(10, 0, -1) または reversed(range(10))。後者は range オブジェクトを返すので効率的。
Q: list と range のメモリ差は?
A: range(10**6) は数十バイト、list(range(10**6)) は約 8 MB。巨大ループでは range 直接渡しが推奨。