【Python デザインパターン】Iteratorパターン
目次
Iteratorパターン
Pythonで配列(list,tuple)の要素を順にコンソールに出力する場合を考えます。
index(添え字)を使ってリストの中身を順にスキャンしていく場合はこのように書きます。
char_list = ["a","b","c","d","e","f","g"] for i in range(len(char_list)): print(char_list[i])
配列は要素の集合で、indexを指定することで複数ある要素の中から1つを選び出すことができます。
この選び出す方法をパターン化(抽象化&一般化)したものをIteratorパターンと呼びます。
またIteratorは反復子とも呼ばれます。
サンプルプログラム
0~10の数値をもつ数値の集合Numbersの要素を順に出力するサンプルプログラムを読んでみましょう。
クラス図
Aggregateクラス(インターフェイス)
class Aggregate: def iterator(self): return
Aggregateクラスはiteratorメソッドだけを提供します。
このクラス単体では使用せずインターフェイスとして利用します。
Aggregateクラスを実装した集合体用クラスに対応したiteratorを作成するためのものです。
Iteratorクラス(インターフェイス)
class Iterator:
def hasNext(self):
return
def next(self):
return
Iteratorクラスは基本的に次の要素が存在するか確認するhasNextメソッド(戻り値はbool)と、
次の要素を返すnextメソッドを提供します。
またnextメソッドは次の要素を返すと同時に内部の状態を進める役割も果たします。
Numbersクラス
class Numbers(Aggregate): def __init__(self): self.numbers = [0,1,2,3,4,5,6,7,8,9,10] def iterator(self): return NormalIterator(self.numbers)
NumbersクラスはAggregateの実装です。
数値を順に出力するイテレータをiteratorメソッドで作成します。
NormalIteratorクラス
class NormalIterator(Iterator):
def __init__(self,numbers):
self.numbers=numbers
self.index = 0
def hasNext(self):
if self.index < len(self.numbers):
return True
else :
return False
def next(self):
number = self.numbers[self.index]
self.index +=1
return number
NormalIteratorはIteratorの実装です。
数値の集合を先頭から順に進めるイテレータです。
Iteratorクラスで説明したようにnextメソッドでは内部のindexで指定された要素を取得し、
内部の状態を次に進める処理を行っています。
サンプルコード全般
class Aggregate:
def iterator(self):
return
class NormalIterator(Iterator):
def __init__(self,numbers):
self.numbers=numbers
self.index = 0
def hasNext(self):
if self.index < len(self.numbers):
return True
else :
return False
def next(self):
number = self.numbers[self.index]
self.index +=1
return number
class Numbers(Aggregate):
def __init__(self):
self.numbers=[0,1,2,3,4,5,6,7,8,9,10]
def iterator(self):
return NormalIterator(self.numbers)
if __name__ == '__main__':
numbers = Numbers()
iterator = numbers.iterator()
while iterator.hasNext():
print(iterator.next())
実行してみてください。
数値が0~10まで順に出力されるはずです。
このように要素の集合と操作を切り分けることによって柔軟なプログラムを書くことができます。
Iteratorのその他の拡張
Iteratorは要素をどのように操作し取得させるかの機能を提供します。
今回のサンプルでは順に出力するというものでしたが、
下記のように偶数、奇数のIteratorを作成し要素の取得の方法を変えることもできます。
偶数のIterator(OddIterator)
class OddIterator(Iterator):
def __init__(self,numbers):
self.numbers=numbers
self.index = 0
def hasNext(self):
if self.index < len(self.numbers):
return True
else :
return False
def next(self):
number = self.numbers[self.index]
self._countup()
return number
def _countup(self):
while True:
self.index += 1
if self.index > len(self.numbers) - 1:
break
elif self.numbers[self.index] % 2 == 0:
break
奇数のIterator(EvenIterator)
class EvenIterator(Iterator):
def __init__(self,numbers):
self.numbers=numbers
self.index = 0
def hasNext(self):
if self.index < len(self.numbers):
if self.numbers[self.index] == 0:
self._countup()
return self.hasNext()
return True
else :
return False
def next(self):
number = self.numbers[self.index]
self._countup()
return number
def _countup(self):
while True:
self.index += 1
if self.index > len(self.numbers) - 1:
break
elif self.numbers[self.index] > 0 and self.numbers[self.index] % 2 == 1:
break
メモ
Iteratorパターンについて書きましたが、
実はPythonにはfor var in list:と書けるように
__iter__や__next__メソッドが定義されています。
https://docs.python.org/ja/3/library/stdtypes.html#typeiter