pythonのイテレータって、結構重宝する機能な気がして個人的には好きなんですが、
バージョン毎に挙動が違ってちょっとややこしい。
↑こちらの記事にたどり着いてスッキリしました。
python3.7におけるイテラブルなクラス
class A(object):
def __init__(self):
self.no_list = [1, 2, 3]
def __iter__(self):
for no in self.no_list:
yield no
else:
return
a = A()
for no in a:
print(no)
for no in a:
print(no)
■実行結果
1
2
3
1
2
3
イテレータは、対象を配列のように扱えるようにします。
クラスにイテレータを実装すると、クラス変数はまるで配列であるかのように
for in 構文を使えます。
二回実行しても、イテレータはちゃんとリセットされてるので、
また配列の先頭から処理されます。
python3.6系以前
class A(object):
def __init__(self):
self.no_list = [1, 2, 3]
def __iter__(self):
for no in self.no_list:
yield no
else:
raise stopIteration()
3.6系以前だとこんな感じ。配列の終端を例外で通知していた。
例外を柔軟に使ってて、これはこれで良い気がするんだけど、
3.7系でこれをやると配列の終端に達した時に、本当に例外がアプリコードへスローされます。
RuntimeError: generator raised StopIteration
つまり、for in 構文の外側でtry/exceptしないといけません。
せっかくクラス変数が配列のように直感的に扱えるようになるのに、これでは台無しです。
ということでpython3.7系では最初のように記述するのが正解です。
python3.7系では、例外は例外なくアプリへスローすべき、というポリシーになったんでしょうか。
個人的には3.6系以前の柔軟な例外の使い方も好きなんですが・・・