Python / range() / 連続する整数や等間隔の整数を作る
Pythonのrange()は、一定間隔の整数列を表す不変シーケンスを作ります。開始値は含み、終端の境界stopは含みません。stepの符号で増加・減少を指定します。全要素を格納するリストや、反復で消費されるジェネレーターとは異なります。
start・stop・stepの基本規則
rangeの公式説明にはrange(stop)、range(start, stop)、range(start, stop, step)があります。省略時のstartは0、stepは1です。引数は整数か整数インデックス規約に対応するオブジェクトで、通常の実数や数値文字列を自動変換しません。
Python 3で各例の全体をUTF-8のrange_example.pyに保存し、python range_example.py、環境に応じてpython3で実行します。内容を置き換えて独立に試せます。小さな範囲はlist()で全要素を確認します。
print(list(range(4)))
print(list(range(1, 6)))
print(list(range(1, 10, 2)))
期待される出力:
[0, 1, 2, 3]
[1, 2, 3, 4, 5]
[1, 3, 5, 7, 9]
range(4)は0~3、range(1, 6)は1~5です。増加・間隔1で5を含めるならstopを6にします。間隔2では最後がstopの直前の整数になるとは限らず、間隔と境界の両条件を満たす値までです。
負のstepと空の範囲
正のstepではstop未満、負のstepではstopより大きい値を含みます。減少には負の間隔が必要です。方向が境界に合わなければ、エラーではなく空の範囲になります。
print(list(range(10, -5, -3)))
print(list(range(5, 0, -1)))
print(list(range(5, 0)))
print(list(range(0, 5, -1)))
print(list(range(3, 3)))
[10, 7, 4, 1, -2]
[5, 4, 3, 2, 1]
[]
[]
[]
range(10, -5, -3)は10、7、4、1、-2です。次の-5はstop自身なので除外します。5から1へ下げるならrange(5, 0, -1)です。開始と終端が同じ場合も空で、その範囲のループ本体は一度も実行されません。
リストではなくても添字と反復が使える
rangeの表示は全要素ではなく範囲の表現です。境界と間隔から値を計算し、長さ・添字・スライス・所属判定に対応します。不変なので添字への代入で要素を変更できません。
numbers = range(2, 10, 2)
print(numbers)
print(len(numbers))
print(numbers[0], numbers[-1])
print(list(numbers[1:3]))
print(6 in numbers, 7 in numbers)
print(list(numbers))
print(list(numbers))
range(2, 10, 2)
4
2 8
[4, 6]
True False
[2, 4, 6, 8]
[2, 4, 6, 8]
同じrangeを2回リストにしても同じ要素が得られます。range自体は消尽するジェネレーターではありません。iter(numbers)で別に作るイテレーターは消費されるため区別します。スライスもrangeを返し、例では確認のためリスト化しています。
stepが0・実数・文字列の場合のエラー
間隔0は進行を定義できずValueErrorです。3.0は整数に見えてもfloat、"3"は文字列なので、どちらもTypeErrorになります。
for arguments in ((1, 5, 0), (3.0,), ("3",)):
try:
print(range(*arguments))
except (ValueError, TypeError) as error:
print(type(error).__name__)
ValueError
TypeError
TypeError
整数文字列を受け付けるなら別途検証してint()で変換します。実数を無条件に切り捨てると意図しない範囲になるので、入力方針を先に決めます。この例外処理は3つの不正入力の比較であり、失敗を無視して成功扱いにする方法ではありません。
反復回数と項目の番号に合わせて選ぶ
rangeを使う反復は回数や整数の段階が必要なときに適します。項目だけ必要ならリストを直接反復し、番号も必要ならenumerate()で添字計算を減らせます。
for number in range(1, 4):
print("Step", number)
names = ["Ada", "Bo"]
for number, name in enumerate(names, start=1):
print(number, name)
Step 1
Step 2
Step 3
1 Ada
2 Bo
最初は1~3の3段階です。次のstart=1は番号の開始を変えるだけで、先頭項目を飛ばしません。実際の添字や位置の計算が必要ならrange(len(items))も使えます。
巨大な範囲と実際の処理資源を区別する
整数リスト全体を保存せず大きな境界を表せますが、全要素の処理時間は省略できません。CPythonではlen()が表せる長さの上限により、rangeを作れても長さの計算でOverflowErrorになる場合があります。
import sys
numbers = range(sys.maxsize + 1)
print(numbers[0])
print(numbers[-1] == sys.maxsize)
try:
print(len(numbers))
except OverflowError:
print("OverflowError")
0
True
OverflowError
例は先頭・末尾と長さのエラーだけを調べ、全体を走査しません。sys.maxsizeは環境によって異なります。巨大な範囲を安易にlist()にせず、必要な区間だけ反復するか順次処理します。




