Python3 – __iter()__によるイテレーターの実装

標準形

Pythonの特殊メソッド__iter____next__を使ってオブジェクトのイテレーターをつくることができる。ジェネレーターがyield文によって任意の値を生成するのに対して、イテレーターはコレクションの要素を順次取り出すときなどに有用。

__iter____next__の2つのメソッドを持ったオブジェクトがfor文で参照されるたびに、以下のように動作する。

  1. forを始める前に__iter__メソッドが実行される
  2. forブロックのループのたびに__next__メソッドが実行される

2つのメソッドの書き方は以下の通り。

__iter__
戻り値としてオブジェクト自身(self)を返す。
__next__
イテレートされるべきプロパティを変更し、戻り値として現在値を返す。もし終了条件に合致しいている場合、イテレート終了の例外を発する。

次の例では、1から初めて最初に設定した値まで1ずつ増える数列のイテレーターをつくっている。

最初の__init__メソッドでは引数から数列の最大値をプロパティにセット。

__iter__メソッドはカウンタになるプロパティに初期値をセットして、selfを返す。

__next__メソッドはそれが呼ばれるたびに次のことを行う。

  • カウンタ値が最大値を超えていたらforブロックから抜け出るよう例外を返す
  • 現在のカウンタ値を返す
  • カウンタ値をインクリメントする

forブロックから抜け出るための例外はStopIterationが準備されていて、forブロックがこの例外を受け取ると、エラーを発生させることなくforブロックの次の処理に移る。

インスタンス変数のイテレーターの取得

たとえばあるクラス内にリストがあって、リストそのものの構造は安全に守ったまま、その要素にアクセスする方法を考えてみた。

インスタンス変数のリストそのものやgetterなどで取得したリストへの参照をメソッドで返すと、リストそのものの操作までできてしまうが、それを防ぎたい。

そこで、インスタンス変数のイテレーターを生成するクラスを元のクラスのインナークラスとして準備して、外部へはイテレーターのインスタンスを渡すようにしてみた。

インナークラスでなくてもできるが、元のクラスのインスタンス変数の構造と密接に関連しているなら、インナークラスでまとめた方が明快だと思う。

 

 

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です