Pythonのenumerate()を使いこなす
目次
Pythonのenumerateの使い方
プログラミング言語のPython(パイソン)にはシーケンスやイテレーターを走査するための組み込み関数enumerate()があります。
このenumerate()
を使うとfor
文でリストなどの添え字と要素を同時に取り出すことが出来ます。
Pythonのfor
文は独特な記法になっているため添え字の扱いに工夫が必要ですが、enumerate()
を使えばストレスなく添え字を取り出すことが可能です。
この記事ではenumerate()
の使い方を解説します。
具体的には↓を見ていきます。
enumerate()の概要
enumerate()の構造
enumerate()の使い方
独自enumerate()の実装
ソースコードの解析
enumerate()の概要
enumerate()
はPythonの組み込み関数として定義されています。
公式のドキュメントは↓です。
enumerate()
はリストやタプルなどをfor
文で回す時に、要素の添え字が欲しくなった場合に使う組み込み関数です。
for
文でリストやタプルなどを走査するときに、このenumerate()
を使えば簡単に走査中の要素の添え字を取り出すことが出来ます。
Pythonを起動してenumerate
をprint()
で出力すると↓のように表示されます。
>>> print(enumerate) <class 'enumerate'>
enumerate()
は「組み込み関数」というカテゴリに分類されていますが、その実体は↑を見てもわかるようにクラスです。
enumerate
クラスのコンストラクタにリストやタプルなどを渡すと、enumerate()
はオブジェクトを生成しその状態を初期化します。
そしてfor
文でオブジェクトとして参照されたときに設定されているリストやタプルなどを走査するという仕組みです。
これらのコードはPythonではなく実装レベルの言語で書かれています。
たとえばPythonの実装がCPythonであればenumerate()の処理はC言語で書かれています。
このためクラスとは言ってもその動作はPythonのクラスに比べて非常に早くなっています。これが「組み込み」に分類されるゆえんかなと推測できます。
enumerate()の構造
enumerate()
は↓のような構造になっています。
enumerate(iterable, start=0)
enumerate()
は引数を最大で2つ取り、1つの返り値を返します。
iterable(第1引数)
enumerate()
の第1引数には走査対象のオブジェクトを渡します。
これはリストやタプルなどです。
シーケンスやiterator
, あるいは__iter__
を実装しているオブジェクトを渡すことが出来ます。
start(第2引数)
enumerate()
の第2引数には添え字の開始点を渡します。
たとえばこのstart
の値が3
であれば、for
文で参照できる添え字は3
から始まります。
enumerate()の使い方
enumerate()
は↓のように使います。
lis = ['cat', 'dog', 'bird'] for i, v in enumerate(lis): print(i, v)
↑のコードではlis
というリストをenumerate()
で参照しています。
↑のコードの実行結果は↓のようになります。
0 cat 1 dog 2 bird
↑のようにenumerate()
を使うと添え字と要素を同時に取り出すことが可能です。
開始点の指定
添え字の開始点(start
)を指定する場合は↓のようにします。
lis = ['cat', 'dog', 'bird'] for i, v in enumerate(lis, 3): print(i, v)
↑のコードの出力は↓のようになります。
3 cat 4 dog 5 bird
独自オブジェクトを走査する
クラスで独自オブジェクトを作り、そのオブジェクトをenumerate()
で走査させたい場合は↓のような実装が考えられます。
class MyList: def __iter__(self): yield 'cat' yield 'dog' yield 'bird' mylis = MyList() for i, v in enumerate(mylis): print(i, v)
↑のようにクラスの__iter__()
メソッドを実装し、ジェネレーターやiter()
を返すようにするとそのオブジェクトはenumerate()
で参照できるようになります。
↑の場合、__iter__()
でyield
を実行し、ジェネレーターを生成しています。
↑のコードの出力は↓のようになります。
0 cat 1 dog 2 bird
独自enumerate()の実装
enumerate()
を自分で作りたい場合は↓のような実装例が考えられます。
class myenumerate: def __init__(self, sequence, start=0): self.sequence = sequence self.start = start def __iter__(self): n = self.start for elem in self.sequence: yield n, elem n += 1 lis = ['cat', 'dog', 'bird'] for i, el in myenumerate(lis, 3): print(i, el)
↑のコードのmyenumerate()
は組み込みのenumerate()
と同じ動作をします。
しかし動作については組み込みのほうに比べて非常に遅いです。
これは組み込みのenumerate()
がC言語で書かれているのに対して、↑のmyenumerate()
はPythonで書かれているためです。
実用性があるかどうかはわかりませんが、使用する場合は速度にだけ注意が必要と言えます。
ソースコードの解析
enumerate()
はCPythonによる実装の場合、enum_new()
関数が最初に呼ばれます。
これはObjects/clinic/enumobject.c.h
で定義されています。
enum_new()
では引数を取り出して、最終的にenum_new_impl()
を呼び出しています。
enum_new_impl()
はObjects/enumobject.c
で定義されています。
enumerate()
で次の要素を生成するときに呼ばれるのはenum_next()
です。
この関数では最終的に添え字とオブジェクトを生成し、それをタプルに包んで返しています。
おわりに
今回はenumerate()
の使い方を見て見てみました。
enumerate()
はリストなどの要素を添え字と一緒に取り出したい時に便利な組み込み関数です。
添え字が必要になったら使ってみてください。