これはなに
Effective Python 第2版 、項目7「rangeではなくenumerateを使う」のまとめ。
ポイント
enumerate
を使えば、イテレータでループしつつ、要素のインデックスも取り出せるrange
でインデックスをループさせるより、enumerate
を使ったほうが簡潔enumerate
の第2引数で、インデックスの開始番号を指定できる
range
とは
range
はPythonの組み込み関数のひとつ。ループ処理に便利。
for i in range(10):
print(i)
リストをループさせる
Pythonのlist
は配列。これをループさせるときは、シーケンスを直接ループできる。
languages = ["python", "golang", "VHDL", "C++"]
for lang in languages:
print(lang)
リストをループさせつつ、インデックスも取り出すことを考える
リストをループさせつつ要素のインデックスを得たい場合を考える。
range
を使うと下記のように書ける。
languages = ["python", "golang", "VHDL", "C++"]
for i in range(len(languages)):
lang = languages[i]
print(f"{i + 1} : {lang}")
ただし、上記の書き方はステップが多く読みにくい。
Pythonには、こういう時に便利な組み込み関数enumerate
がある。
enumerate
とは
enumerate
はPythonの組み込み関数のひとつ。遅延評価ジェネレータでイテレータをラップし、ループのインデックスとイテレータの次の値の対をyield
する。
公式ドキュメント によると、下記の記述と等価らしい。
def enumerate(iterable, start=0):
n = start
for elem in iterable:
yield n, elem
n += 1
つまり、enumerate
は、「ループのインデックスとイテレータの次の値の対」を呼び出すたびに生成(遅延評価)するジェネレータを生成する。
呼び出すたびに生成するため、メモリを圧迫せずに処理できる。
enumerate
はジェネレータを生成するため、next
を用いて次の値を取得できる。
languages = ["python", "golang", "VHDL", "C++"]
it = enumerate(languages)
print(next(it)) # (0, 'python')
print(next(it)) # (1, 'golang')
range
ではなくenumerate
を使う
リストをループさせつつ要素のインデックスを得たい場合、enumerate
を使うと下記のように書ける。
languages = ["python", "golang", "VHDL", "C++"]
for i, lang in enumerate(languages):
print(f"{i + 1} : {lang}")
range
を使った場合と比較すると、enumerate
を使ったほうが簡潔に書ける。
languages = ["python", "golang", "VHDL", "C++"]
# enumerateを使う
for i, lang in enumerate(languages):
print(f"{i + 1} : {lang}")
# rangeを使う
for i in range(len(languages)):
lang = languages[i]
print(f"{i + 1} : {lang}")
enumerate
のカウント開始の数を変更する
enumerate
の第2引数にカウントを開始する数を指定できる。これを利用すると、先のコードはより簡潔に書ける。
languages = ["python", "golang", "VHDL", "C++"]
for i, lang in enumerate(languages, 1):
print(f"{i} : {lang}")