数列を生成する便利な道具
range() がやることはたった一つ、整数の連続した並びを作り出すことです。決まった回数だけ繰り返したい、あるいは数値の区間を順番にたどりたい——そんなときの for ループの相棒として、まず最初に候補に挙がる関数です。
一番シンプルな書き方は、引数を1つだけ渡すパターン。この引数が stop(終了値)になります。
Output:
0
1
2
3
4
初心者がよくつまずくポイントが2つあります。
- カウントは 0 から始まる。
range(5)は 0 から始まる 5 個の数値を返します。 - 終了値は含まれない。
range(5)は 5 の 手前 で止まり、5 自体は含みません。
このルールは、Python のスライス、インデックス、range のどれでも一貫しています。「stop は含まない」という感覚さえ身につけば、もう迷うことはありません。
3つの書き方
range() は、引数を 1 個・2 個・3 個のいずれかで呼び出せます。
ステップとは、1回のジャンプで進む幅のこと。range(0, 20, 4) は4つおきの数を生成します。「1つ飛ばし」や「10個ごとのサンプル」が必要になったときは、この挙動を思い出してください。
カウントダウンする(逆順ループ)
ステップには負の値も指定できるので、逆方向に数えることも可能です。
改めて確認しておくと、stop は含まれない点に注意してください。range(10, 0, -1) は 0 の 手前 で止まるので、0 そのものは含まれません。0 まで含めたい場合は、stop を -1 に指定します。
rangeは遅延評価される
Python 3のrange()は、数値のリストをメモリ上に作るわけではありません。返ってくるのは軽量なrangeオブジェクトで、必要になったタイミングで1つずつ数値を生み出してくれます。だからこそ、次のように書けるわけです。
range で10億個の数列を作っても、メモリはほぼ食いません。値は for ループが要求したタイミングで、その都度生成される仕組みだからです。
数値を本当に「リスト」として扱いたいとき——たとえば中身を書き換えたい、ソートしたい、基本的な使い方を超えてインデックスで自由にアクセスしたい場合——は、次のように明示的に変換します。
ほとんどの場合、リストに変換する必要はありません。for i in range(...) をそのまま書けば動きます。
よく使うパターン
ここでは、実際に何度も書くことになる定番の書き方を紹介します。
同じ処理を n 回繰り返す。
_ は「この値は使わない」という慣例的な書き方です。Python が強制しているわけではありませんが、読み手はこの意図をすぐに理解してくれます。
シーケンスのインデックスとして使う
基本的には range(len(...)) より enumerate() を使うほうがおすすめです。ただ、どうしてもインデックスだけがほしい場面ではこう書けます。
それでも、多くの場面では enumerate(items) を使うほうがスッキリ書けます。
1つ飛ばしで要素を処理する。
これは a、c、e と出力します。ただし、こういった単純なスライスなら、スライス構文を使った items[::2] の方がよりシンプルに書けます。
数値のリストをサクッと作る。
これは内包表記と呼ばれる書き方で、後ほど詳しく解説しますが、ここで数値を用意しているのは range の役割です。
range()にできないこと
ハマりやすいポイントが2つあります。
rangeは整数しか生成できません。 0.0 から 1.0 まで 0.1 刻みといった小数ステップが必要な場合は、numpy.arangeを使うか、自前でカウンタを用意したループを書きましょう。rangeは任意のイテラブルには使えません。 あくまで整数専用です。リストに対して「range したい」と思ったときは、たいていenumerateを使うか、リストをそのまま回すのが正解です。
まとめて使ってみる
ここまで紹介したいくつかのパターンを、ひとつの例でまとめて使ってみましょう。
range を使った二重ループでグリッドを作っています。どちらのループも range(1, 6) で1からスタートしているのがポイント。1〜5のラベルが欲しいので、こうしています。
いよいよコレクションへ
ここまでで、条件分岐・2種類のループ・range を一通り押さえました。これだけあれば、どんなコレクションでも自在に扱えます。次章ではいよいよコレクションそのもの——リスト、タプル、セット、辞書を見ていきましょう。
よくある質問
Pythonのrange()は何をする関数ですか?
整数の連続した並びを生成する関数です。range(n) なら0からn-1まで、range(start, stop) ならstartからstop直前まで、range(start, stop, step) ではstep幅を指定できます。stepにマイナスの値を渡せばカウントダウンも可能です。
range()はリストを作っているのですか?
いいえ。Python 3の range() は、必要になったタイミングで数値を返す軽量な「rangeオブジェクト」を返します。だから range(10**9) でも一瞬で動くんです(10億個の整数をメモリに確保しているわけではありません)。リストが欲しい場合は list(range(...)) で明示的に変換してください。
range()で逆順にカウントダウンするには?
stepに負の値を指定します。range(10, 0, -1) なら10, 9, 8, ..., 1が得られます。ただし stop の値は常に「含まれない」ので、0まで含めたいときは range(10, -1, -1) と書く必要がある点に注意してください。