こんにちは!フリーランスの長野です。
イテレータって使っていますか?
リストや辞書などの要素が集まったデータを操作する場合に使うと便利な機能です。
この記事では、イテレータについて
・イテレータとは
・イテレータの使い方
という基本的な内容から、
・itertoolsの使い方
・イテレータの実装
など応用的な内容についても解説していきます。
今回はイテレータについて、使い方をわかりやすく解説します!
※ この記事のコードはPython 3.7で動作確認しました。
本記事を読む前に、Pythonがどんなプログラミング言語なのかをおさらいしておきたい人は次の記事を参考にしてください。
→ Pythonとは?特徴やできること、活用例をわかりやすく簡単に解説
なお、その他のPythonの記事についてはこちらにまとめています。
イテレータとは
イテレータとは次の要素にアクセスすることを繰り返すインターフェースのことを言います。
リストやタブル、辞書などのコレクション型の要素に順にアクセスし処理する場合に使用します。
イテレータは最初の要素から最後の要素までを順にアクセスする単純な操作ですが、itertoolsモジュールなどを使うことでこれ以外にも便利な操作が可能になります。
また自作のクラスを作成することで、イテレータを行いたい操作にカスタマイズすることも可能です。
イテレータの使い方
イテレータの基本的な使い方について確認していきましょう。
iterの使い方
イテレータオブジェクトを作る場合、iter関数を使用します。
iter関数の引数にはリストや辞書などのコレクション型のオブジェクトを入力します。
それではサンプルコードを確認しながらみていきましょう。
season = ['Spring', 'Summer', 'Fall', 'Winter'] iter_season = iter(season) print(type(iter_season)) # 型を表示して確認 print(next(iter_season)) # 1番目のイテレータを表示後、次のイテレータに進む next(iter_season) # 次のイテレータに進む # イテレータを1つずつ取り出して表示 for i in iter_season: print(i) # イテレータを1つずつ取り出して表示 for i in iter_season: print(i)
実行結果:
<class 'list_iterator'> Spring Fall Winter
このサンプルコードではseasonという文字列のリストを使用しています。
iter関数を使ってリストのイテレータを生成しています。
next関数を使うと次のイテレータへ進みます。
1番目のイテレータをprint関数で表示したあとnext関数で次のイテレータへ進み、その後for文を使って一つずつイテレータを表示しています。
for文などのループを使う場合、イテレータはnext関数を記述しなくても自動で次のイテレータへと進むようになっています。
したがって、リストの2番目の「Summer」は表示されずに次の「Fall」以降がfor文を使って表示されています。
また、その後にもfor文を使ってイテレータを表示をしようとしていますが、表示されていません。
これは1回目のfor文で最後の要素まで進んだためで、2回目のfor文ではイテレータの要素がないために表示されていません。
reversedの使い方
次にreversed関数の使い方について確認していきましょう。
reversed関数はリストなどのコレクション型データを最後から逆順に処理したい場合などで使われます。
season = ['Spring', 'Summer', 'Fall', 'Winter'] rev_season = reversed(season) print(type(rev_season)) # 型を表示して確認 next(rev_season) # 次のイテレータに進む # イテレータを1つずつ取り出して表示 for i in rev_season: print(i) # イテレータを1つずつ取り出して表示 for i in rev_season: print(i)
実行結果:
<class 'list_reverseiterator'> Fall Summer Spring
このサンプルコードでは、reversed関数を使ってrev_seasonオブジェクトを生成しています。
rev_seasonオブジェクトの型を表示して確認すると、list_reverseiteratorとなっています。
reverseiteratorもiteratorと同様に扱います。
nextを使うと、コンテナオブジェクトの要素を先頭から取り出してくれます。
その後、for文を使って一つずつイテレータオブジェクトのもつ要素を表示しています。
next関数を使って次に進ませていますので逆順にした最初の要素「Winter」は表示されず、「Fall」以降がfor文を使って逆順で表示されています。
こちらもfor文を2回使って表示するようにしていますが、2回目のfor文で表示されていないのは1回目のfor文でイテレータが最後の要素まで達しているためです。
※イテレータオブジェクトは使い捨てなので、空になったら新しく作り直さないといけません。
itertoolsの使い方
イテレータを使った便利な機能としてitertoolsモジュールが用意されています。
itertoolsモジュールのchain、zip_longest、islice、teeそれぞれのメソッドの使い方についてサンプルコードを確認していきましょう。
itertoolsモジュールを使うにはインポートする必要があります。
chainの使い方
import itertools season = ['Spring', 'Summer', 'Fall', 'Winter'] index = [0, 1, 2, 3] # 1つのシーケンスに結合 it = itertools.chain(index, season) print(type(it)) for i in it: print(i)
実行結果:
<class 'itertools.chain'> 0 1 2 3 Spring Summer Fall Winter
itertoolsモジュールのchainメソッドを使用して、2つのリストをシーケンシャルに結合しています。
chainメソッドの引数に結合する2つのリストを入力しています。
zip_longestの使い方
import itertools season = ['Spring', 'Summer', 'Fall', 'Winter'] index = [0, 1, 2, 3] # 複数の要素を結合 it = itertools.zip_longest(index, season) print(type(it)) for i in it: print(i)
実行結果:
<class 'itertools.zip_longest'> (0, 'Spring') (1, 'Summer') (2, 'Fall') (3, 'Winter')
zip_longestメソッドを使用して、2つのリストの要素同士をセットにして結合しています。
zip_longestの引数に結合する2つのリストを入力しています。
isliceの使い方
import itertools # 指定した要素を返す it = itertools.islice(itertools.count(), 0, 10, 2) print(type(it)) for i in it: print(i)
実行結果:
<class 'itertools.islice'> 0 2 4 6 8
isliceメソッドを使用して要素を抽出しています。
countメソッドで生成される正の整数値の中からゼロから10未満の要素を2つおきに抽出しています。
isliceメソッドの第1引数には操作したいイテレータを入力します。
第2引数にはスタートするインデックス数を入力します・
第3引数には終わりのインデックス数を入力します。
第4引数には何個おきに抽出するかステップ数を入力しています。
第3引数と第4引数は省略可能で第3引数を省略した場合、インデックス0(ゼロ)からスタートして第2引数のインデックス未満まで抽出します。
第4引数を省略した場合、ステップして抽出されることはありません。
teeの使い方
import itertools # イテレータの複製 it = itertools.islice(itertools.count(), 3) it1, it2 = itertools.tee(it) print(type(it1)) for i in it1: print('it1:' + str(i)) for i in it2: print('it2:' + str(i))
実行結果:
<class 'itertools._tee'> it1:0 it1:1 it1:2 it2:0 it2:1 it2:2
teeメソッドを使用して同じイテレータを複数返しています。
teeメソッドの引数には複製する元となるイテレータを入力します。
このようにitertoolsモジュールのメソッドを使用することでさまざまな要素の操作を簡単に記述することができます。
イテレータの実装
これまでは標準で準備している関数やモジュールを使ってイテレータを操作してきました。
イテレータは自作のクラスを使って実装することもできます。
サンプルコードを確認して使い方をみていきましょう。
class MyIter: def __init__(self, objs): self.objs = objs self.index = 0 def __iter__(self): return self def __next__(self): if self.index >= len(self.objs): raise StopIteration value = self.objs[self.index] index = self.index self.index += 2 return index, value my_iter = MyIter(['Spring', 'Summer', 'Fall', 'Winter']) for i in my_iter: print(i)
実行結果:
(0, 'Spring') (2, 'Fall')
このサンプルコードでは自作のイテレータクラスとなるMyIterクラスを作成しています。
コンストラクタでは引数でオブジェクトを入力しMyIterクラスのobjsオブジェクトに代入しています。
またindex値をゼロで初期化しています。
__iter__メソッドは新しいイテレータを作るときに呼び出されます。
このサンプルコードではコンストラクタで初期設定をしていますので、そのままselfを返しています。
__next__メソッドは次のイテレータに進むときに呼び出されます。
index値がコンストラクタで入力されたオブジェクトの要素数以上になるとStopIterationクラスを使ってイテレータが次に進むのを止めています。
objsオブジェクトの中のindex値の要素をvalueオブジェクトに代入しています。
__next__メソッドではインデックスと要素がセットで出力されるように、index値とvalueオブジェクトを返すように記述しています。
また__next__メソッドでは2つおきに要素が出力されるように、処理の最後にindex値を2カウントアップしています。
このMyIterクラスからmy_iterインスタンスを生成して、for文を使って1つずつイテレータを表示しています。
まとめ
ここでは、イテレータの使い方やitertoolsの使い方などについて説明しました。
イテレータを使うことでリストの逆順の処理やインデックス付きの要素出力など、コレクション型データの操作が簡単な記述で実装できます。
また使用目的にあわせてイテレータのクラスを自作することでカスタマイズする方法についても説明しました。
イテレータの操作を使いこなすことができるようにこの記事を何度も参考にして下さいね!