今回はPythonのrange型についてです。range型といえば「範囲」を扱う型ですが、その範囲にも色々とあります。実際にrange型を作成しつつ、
- 様々なrange型の形
- 操作やメソッド
- for文での使用
などについてお話していこうと思います。
range型の作成方法
新規作成
それではrange型を作成していきます。
range(0,3,1) #range(0,3)
range(3) #range(0,3)
このコードは2行とも同じrange型を作ります。range
コンストラクタ(便宜上range
関数と呼んでもかまいません)の引数は「start」,「stop」,「step」の3つですが、省略して「stop」1つでも作成可能です。
どのような値が作成されるのか、分かりやすいようにリストにしてみましょう。list
コンストラクタの引数にrange
コンストラクタを入れることで、range型をlist型に変換できます。
list(range(3)) #[0, 1, 2]
0以上3未満の整数の範囲が、1刻みで作成されているのが分かります。stopに指定した数値は含まれないので気を付けましょう。
逆順のrange型
今度はrange
コンストラクタの引数を変えて試してみます。
list(range(1,5,2)) #[1, 3] 1以上5未満 2刻み
list(range(7,0,-1)) #[7, 6, 5, 4, 3, 2, 1] 7以下0超過 -1刻み
list(range(-4,6,4)) #[-4, 0, 4] -4以上0未満 4刻み
引数が整数であれば、負の値でも問題無く使用できます。通常であれば要素は小さい順に並びますが、逆に大きい順に並べたい場合、2行目のように「start」>「stop」であり、かつ「step」が負の値になるよう設定しましょう。
後で少し詳しく説明しますが、reversed
関数を使うことで既成のrange型の順序を逆にすることも可能です。
r = range(3)
print(list(reversed(r))) #[2, 1, 0]
空のrange型
rangeコンストラクタに渡した引数の値が「範囲」と認められないものは中身が空になります。ある意味エラーになるよりたちが悪いので注意してください。
list(range(1,5,-2)) #[] start < stopなのに-刻み
list(range(7,0,1)) #[] start > stopなのに+刻み
list(range(0,0,-1)) #[] start = stop
そして上にも出ていますが、引数として認められるのは整数のみです。
list(range(0.1))
#TypeError: 'float' object cannot be interpreted as an integer
=rangeコンストラクタが受け取れるのはint型のみである
どうしてもfloatを扱いたい場合は、for文やリストなどを使う必要があります。
r = range(1,10,3)
lst = []
for x in r:
lst.append(x/10)
print(lst) #[0.1, 0.4, 0.7]
range型の操作/メソッド
どんな型?
作成されたrange型は「等間隔の整数」を格納する「イミュータブル」な「シーケンス型」です。これは言わばtuple型に近く、tuple型が実装している機能の多くはrange型でも使用可能です。
ただ多少独特な挙動を見せる場合もあるので、どんな操作が可能なのか1つずつ見ていきます。
要素を指定する
r = range(1,101,2) #0~100までの、2刻みのrange型
print(r[18]) #36
print(r[-8]) #86
print(r[34:40]) #range(68, 80, 2)
インデックス番号の指定やスライス表記は、range型でも問題無く使用できます。ただしスライスの結果はrange型になるので、直接全ての数値を確認したい場合は他のコンテナ型に変換しましょう。
print(list(r[34:40])) #[68, 70, 72, 74, 76, 78]
要素数を数える
print(len(r)) #51
おなじみのlen
関数です。他の型と同じように要素数を出力できます。
最大値/最小値を出力する
print(max(r)) #100
print(min(r)) #0
max
関数やmin
関数で、そこに含まれる数値の最大値/最小値を出力します。
start,stop,stepを確認する
r = range(0,101,2)
print(r.start) #0
print(r.stop) #101
print(r.step) #2
こちらはrange型のプロパティ。設定された「start」,「stop」,「step」の値を確認できます。
指定した値があるかどうか調べる
print(58 in r) #True
print(39 in r) #False
print(87 not in r) #True
print(12 not in r) #False
in
演算子、not in
演算子で、指定した値がそこに含まれるかどうかを確認。これも他の型と同様です。
print(r.count(56)) #1
print(r.count(3)) #0
count
メソッドは本来、引数に取った値が呼び出し元の中に「いくつあるか」を調べるメソッドですが、range型で使用すると答えは1か0です。つまり「あるかどうか」を調べることと同義になります。
順序を逆にする
r = range(0,101,2)
rr = reversed(r)
print(list(rr))
#[100, 98, 96, 94, 92, 90,..., 4, 2, 0]
非破壊のreversed
関数はrange型にも使用可能です。ただし、この関数の戻り値は元のrange型ではなくイテレータであることには注意しましょう。
print(rr) #<range_iterator object at 0x00000241180B9BD0>
https://pouhon.net/python-iter/2067/
range型にできないこと
tuple型では可能な「+」や「*」を使った演算ですが、range型には許されていません。
r = range(3)
r2 = range(5)
r3 = r+r2
#TypeError: unsupported operand type(s) for +: 'range' and 'range'
r = range(3)
r2 = range(5)
r3 = r*2
#TypeError: unsupported operand type(s) for *: 'range' and 'int'
公式ドキュメントにはこう書いてあります。
range は共通のシーケンス演算を、結合と繰り返し以外すべて実装します (range オブジェクトは厳格なパターンに従うシーケンスのみを表せ、繰り返しと結合はたいていそのパターンを破るという事実によります)。
つまり「等間隔の整数」で表す「ある一定の範囲」というrange型の大原則を崩してしまう可能性が大きい「+」や「*」は、そもそも使用できませんということです。
for文で使うrange型
最後にrange型のメジャーな使用方法であるfor文を簡単に見ていきます。
for x in range(3):
print("ゴール!")
#ゴール!
#ゴール!
#ゴール!
for 変数 in range(n)
で処理内容をn回繰り返す構文です。これはリストを使用して
for x in [0,1,2]:
としても全く同じ結果になりますが、「回数を指定するだけ」という単純明快な記述は他のどの型にも真似できません。
lst = []
for x in range(1,6):
lst.append(x**2)
print(lst) #[1, 4, 9, 16, 25]
こちらは変数xを処理内容に使った場合。0始まりを変更したい場合は第一引数に0以外を指定しましょう。
コンストラクタの引数を柔軟に変化させることで、リストやタプルで書くには労力がかかる大きな範囲ですら、簡単に扱えるのがrange型の魅力です。