今回は、Pythonのiter()関数の使い方を紹介します。
イテレータとは、それ自体がPythonのオブジェクトをロードするオブジェクトのことで、しばしば使いたいと思うことがあります。
しかし、配列やリストとは対照的に、イテレータは必要なときに必要な分だけオブジェクトをロードするだけです。
これはレイジーローディング、またはストリームベースローディングと呼ばれます。
これは、メモリを節約したい場合や、オブジェクトが非常に大きい場合にオブジェクト全体を一度にロードしない場合に、非常に便利です。
Pythonの基本的な構文 iter()
iter()` 関数を使うと、辞書やリスト、セットなどの反復可能なオブジェクトへのイテレータを生成することができます。
Pythonの iter() 関数の基本的な使い方は以下の通りです。
iterator = iter(iterable)
|
これは iterable オブジェクトから iterator を生成します。
そして、 next(iterator) を使って、 StopIteration 例外を発生させるまでオブジェクトを一つずつロードしていきます。
また、同じイテレータを使用して、再びイテレートすることはできないことに注意してください。
イテレートする前に、Pythonの iter() を使って別のイテレータを生成しなければなりません。
Python の iter() を使う – 簡単な例
ここでは、iter() を使った簡単な例を紹介します。
10個の要素からなるリストを受け取り、1つずつロードしていきます。
a = [i for i in range(10)]
iterator = iter(a)
while True:
try:
out = next(iterator) # Load the next element
print(f"Iterator loaded {out}")
except StopIteration:
# End of loading. Break out of the while loop
print("End of iterator loading!")
break
|
結果は以下の通りです。
Iterator loaded 0Iterator loaded 1Iterator loaded 2Iterator loaded 3Iterator loaded 4Iterator loaded 5Iterator loaded 6Iterator loaded 7Iterator loaded 8Iterator loaded 9End of iterator loading! |
見てわかるように、確かに、StopIteration 例外をキャッチするまで、リストから要素を 1 つずつロードしています!
Python の iter() をカスタムオブジェクトに使用する
先ほど述べたように、Pythonのiter()は反復可能なオブジェクトであれば、どのようなオブジェクトでも使うことができます。
これは、いくつかの条件を満たせば、カスタムオブジェクトにも適用されます。
しかし、Pythonで任意のオブジェクトが反復可能であるための条件とは何でしょうか?
- そのオブジェクトのクラスは
__iter__()メソッドを持たなければなりません。 - そのオブジェクトのクラスが
__next__()メソッドを持っていること。また、終了条件に達した場合はStopIterationException も発生させることが推奨されます。
さて、Python の iter() メソッドはイテレータを構築して、 __iter__() メソッドを呼び出します。
同様に、 next(iterator) はフードの裏で __next__() メソッドを呼び出します。
注意: これらのメソッドを持たないクラスは、少なくとも __getitem()__ メソッド (引数は 0 から整数) を持つ必要があります。
それでは、ある制限値まで整数を生成するカスタムオブジェクトのクラスを書いてみましょう。
class MyClass():
def __init__(self, max_val):
# Set the maximum limit (condition)
# max_val must be a natural number
assert isinstance(max_val, int) and max_val >= 0
self.max_val = max_val
def __iter__(self):
# Called when the iterator is generated
# Initialise the value to 0
self.value = 0
return self
def __next__(self):
# Called when we do next(iterator)
if self.value >= self.max_val:
# Terminating condition
raise StopIteration
self.value += 1
# Return the previously current value
return self.value - 1
# Set the limit to 10my_obj = MyClass(10)
# An iterator to the objectmy_iterator = iter(my_obj)
while True:
try:
val = next(my_obj)
print(f"Iterator Loaded {val}")
except StopIteration:
print("Iterator loading ended!")
break
|
結果は以下の通りです。
Iterator Loaded 0Iterator Loaded 1Iterator Loaded 2Iterator Loaded 3Iterator Loaded 4Iterator Loaded 5Iterator Loaded 6Iterator Loaded 7Iterator Loaded 8Iterator Loaded 9Iterator loading ended! |
見ての通り、カスタムオブジェクトで iter() 関数を使用することができます。
iter__()メソッドはイテレータオブジェクトを生成し、next()` を使ってそれを更新します。
終了条件は、現在の値が最大値よりも大きいときで、このときに StopIteration 例外を発生させます。
この記事もチェック:Pythonのforkメソッドを使って子プロセスの生成や終了を行う方法
iter()でセンチネル値まで値を生成する
Python の iter() には、もう一つ引数を渡すことができます。
この2つ目の引数は sentinel 要素と呼ばれます。
このセンチネル要素を渡すと、生成された値がこのセンチネル値と等しくなるまでイテレータは値を生成し続け、それ以降は StopIteration が発生します。
この後、イテレータの生成は自動的に停止する!
これは、関数から連続したデータが送られてくる場合に非常に便利です。
また、センチネル引数を使用する場合、最初の引数は呼び出し可能でなければならないので、関数も必要です。
iterator = iter(callable_object, sentinel)
|
ここで、 iterator はイテレータであり、戻り値が sentinel と等しくなるまで callable_object を呼び続けることができる。
ここで、 callable_object は関数やメソッド、あるいはラムダであってもよい。
Lambda を callable として使用する簡単な例を見てみましょう。
文字列を入力として、ラムダ関数に渡し、改行のセンチネル要素(‘˶’ᵕᴗᵕ’)になるまで値を生成し続けるというものです。
a = "This is a long string consisting of two lines.
start = 0
size = 1
def func(a):
return a[start: start+size]
iterator = iter(lambda: func(a), ')
# Will generate values until 'for out in iterator:
print(f"Iterator loaded {out}")
start += size
print("Encountered Newline!")
|
結果は以下の通りです。
Iterator loaded TIterator loaded hIterator loaded iIterator loaded sIterator loadedIterator loaded iIterator loaded sIterator loadedIterator loaded aIterator loadedIterator loaded lIterator loaded oIterator loaded nIterator loaded gIterator loadedIterator loaded sIterator loaded tIterator loaded rIterator loaded iIterator loaded nIterator loaded gIterator loadedIterator loaded cIterator loaded oIterator loaded nIterator loaded sIterator loaded iIterator loaded sIterator loaded tIterator loaded iIterator loaded nIterator loaded gIterator loadedIterator loaded oIterator loaded fIterator loadedIterator loaded tIterator loaded wIterator loaded oIterator loadedIterator loaded lIterator loaded iIterator loaded nIterator loaded eIterator loaded sIterator loaded .Encountered Newline! |
このように、イテレータは改行があるまで値を生成しています。
同じプログラムを while ループを使って行い、 StopIteration 例外をキャッチすることもできました。
これは、関数から返される出力のブロックを処理したい場合に非常に便利です。
まとめ
この記事では、Pythonの iter() 関数を使用して、さまざまなオブジェクトの反復表を生成する方法について見てきました。