Pythonのforループを攻略する|range, enumerate, zipの使い方ガイド
Pythonのfor文は、他のプログラミング言語と少し違います。この記事では、Pythonのfor文の基本的な文法を、他の言語のfor文と比較しながら解説します。また、range
, enumerate
, zip
といった機能に焦点をあて、これらの使い方も紹介します。さらにループで注意すべき点についても解説しています。
for文について
他の言語のfor文
C言語などの他の言語では、for文は以下のような感じで書くものだったかと思います。
for(初期化文;判定式;更新文)
もっと古い言語(BASICなど)では、以下のように記述していました。
FOR カウンター変数=初期値 TO 終了値 STEP 増加量
どりたの場合も、for(i = 0; i < 10; i++)のように、初期化、終了条件、増加or減少量といった3つの要素から成り立っているのが一般的にでした。
C++などの言語では、上記以外に範囲forと呼ばれる構文も存在しています。こちらはPythonの構文に少しだけ近いです。
Pythonのfor文
Pythonでは、他の言語のようなfor文はなく、以下のようなfor文だけが存在しています。
for 変数 in イテラブル :
イテラブルとはリストやタプル、辞書、集合などの要素のことです。
なお、このようなfor 要素 : 要素の集合
というfor文はjavaやC++, C#などでも利用することができます。
この記事では、Pythonのfor文について深掘りして解説したいと思います。
イテラブルとは何か?
イテラブルとは、「__iter__
メソッド、または__getitem__
メソッドを持つオブジェクト」です。
実際に、イテラブルを定義してみます。イテラブルの実装は少し難しい部分なので、わからなければ飛ばして読んでもらってかまいません。「こんな感じなんだ」と思ってもらえれば十分です。
下記の例は、__getitem__
メソッドを持つオブジェクトの例です。例ではindexが0~10までの間はindexを返し、範囲を超えたらIndexError
エラーを発生させます。
コードを動作させると0~10までの値が表示されます。
class MyIterable:
def __getitem__(self, index):
if 0 <= index <= 10:
return index
else:
raise IndexError
for e in MyIterable():
print(e)
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10
イテラブルは上記のようなメソッドを持ったオブジェクトなら自作することが可能です。
もう1つ例です。こちらは__iter__
メソッドを持つものです。こちらは、n個目までのフィボナッチ数を返すイテレータです。__next__
メソッドで、index
とs0
, s1
を更新しています。
このプログラムでは、指定した数の数列を出力したらraize StopIteration
で生成を中止しています。結果として、指定した数の数列分だけループを繰り返すことになります。
class MyIterator:
def __init__(self, n):
self.n = n
self.s0 = 1
self.s1 = 1
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= self.n:
raise StopIteration
value = self.s0
self.s0, self.s1 = self.s1, self.s0 + self.s1
self.index += 1
return value
for e in MyIterator(10):
print(e)
# 1
# 1
# 2
# 3
# 5
# 8
# 13
# 21
# 34
# 55
いきなり難しい内容になっていますが、細かいことを知る必要はありません。とりあえず、イタラブルはこんな感じで自作できることは知っておきましょう。
Pythonのfor文の頻出パターン
Pythonのforループでよく使うパターンを紹介します。ここで紹介するのはrange
を使ったパターン、リストやsetを使うパターン、enumerate
を使ったパターン、zip
を使ったパターンです。
range
range()関数を使うことで、開始値、終了値、増加値でループする他の言語のforループのような記述を行うことができます。最もよく使うforループです。
終了のみ指定
終了値のみを指定すると0,1,2…終了値-1までループします。
for i in range(10):
print(i, end=" ")
# 0 1 2 3 4 5 6 7 8 9
開始と終了を指定
開始と終了を指定します。区間としては[開始値, 終了値)までのループとなります。
半開区間の記号に注意してください。range(1,3)
と指定した場合、[1, 3)の区間のループ、つまり1,2のループとなり3は含まれません。
5,4,3,2,1,0とiを更新したい場合は、range(5, -1, -1)
となります。range(5, 0, -1)
とすると1
までしかループしないので注意です。
for i in range(5, 10):
print(i, end=" ")
# 5 6 7 8 9
開始、終了、ステップを指定
開始、終了、ステップを指定できます。ステップをしてすることで降順にすることも可能です。終了条件に注意してください。
for i in range(10, 0, -1):
print(i, end=" ")
# 10 9 8 7 6 5 4 3 2 1
リスト、辞書、セット
リスト
リストの要素を1つずつ取り出す例です。
a = [1,2,3,4,5]
for e in a :
print(e, end = " ")
# 1 2 3 4 5
set
セット(set)の値を1つずつ取り出す例です
a = set([1,3,10,4,5,6,7,8,1,2,3,4])
for e in a :
print(e, end = " ")
# 1 2 3 4 5 6 7 8 10
辞書(dict)
辞書の要素でループする例です。何も指定しないとkeyが変数e
に代入されます。
a = {"a":1, "b":2, "c":3}
for e in a:
print(e, end = " ")
# a b c
a.keys()
とした場合は、何も指定しない場合と同様になります。
a = {"a":1, "b":2, "c":3}
for e in a.keys():
print(e, end = " ")
# a b c
a.values()
と指定するとe
には要素の値が代入されます。
a = {"a":1, "b":2, "c":3}
for e in a.values():
print(e, end = " ")
# 1 2 3
enumerate
enumerate
を使うことで、要素と同時にループ回数を受け取ることが可能です。リストの要素数だけループする場合に、要素番号も欲しい場合などに重宝します。
a = ["a", "b", "c"]
for i, e in enumerate(a):
print(i, e)
# 0 a
# 1 b
# 2 c
zip
zip
を使うことで、2つの要素から同時に値を取り出すことが可能です。2つの要素をペアとして同時に取り出したい場合に便利です。
a = ["a", "b", "c"]
b = [1, 2, 3]
for x, y in zip(a, b):
print(x, y)
# a 1
# b 2
# c 3
enumerate, zipは便利なのでよく使います。覚えておいて損はないです。
for文で注意すべき点
リストの要素でループする場合の注意点
for x in リスト
のような形式で、リストの要素に対してループする場合、注意点があります。
例えば、以下のようなプログラムを実行するとどうなるでしょうか?
a = [1,2,3,4,5]
for e in a :
e += 10
print(a)
プログラムとしては、各要素に10を足しているのでa=[11,12,13,14,15]
となることを期待するかもしれません。
しかしながら、結果はa=[1,2,3,4,5]
のままです。
e
には、a
の要素が複製(コピー)されて渡されるため、e
を書き換えてもa
の要素は変更されないことに注意する必要があります。
a
の要素を変更したければ、例えば、以下のように書き換える必要があります。
a = [1,2,3,4,5]
for i in range(len(a)):
a[i] += 10
print(a)
このように、要素を受け取ってループする場合には注意が必要です。
まとめ
以上、Pythonのfor文について解説しました。javascriptなどの他の言語からPythonに入るとfor文の書き方の違いに戸惑うことがありますが、基本はfor ~ in ~
しかないので実は簡単です。