次のコードはPython 3.7で実行すると RuntimeError になります。
def tentimes():
i = 0
while True:
if i == 10:
raise StopIteration
yield i
i = i + 1
for i in tentimes():
print(i)
0
1
2
3
4
5
6
7
8
9
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-1-20f0585f0e57> in tentimes()
4 if i == 10:
----> 5 raise StopIteration
6 yield i
StopIteration:
The above exception was the direct cause of the following exception:
RuntimeError Traceback (most recent call last)
<ipython-input-2-ade91eb5a83d> in <module>
----> 1 for i in tentimes():
2 print(i)
3
RuntimeError: generator raised StopIteration
これは組み込み例外 — Python 3.7.3 ドキュメント に記述があり、PEP 479 -- Change StopIteration handling inside generators がデフォルトで有効化されているためです。
同様のコードは次のように修正すると動きます。
def tentimes():
i = 0
while True:
if i == 10:
return
yield i
i = i + 1
for i in tentimes():
print(i)
0
1
2
3
4
5
6
7
8
9
Pythonのイテレータとジェネレータ - Qiitaの記事にあるような実装で raise StopIteration
しても RuntimeError にはなりません。
class MyRange(object):
def __init__(self, start, end):
self._i = start
self._end = end
def __iter__(self):
return self
def __next__(self):
if self._i == self._end:
raise StopIteration
value = self._i
self._i = self._i + 1
return value
my_range = MyRange(0, 10)
for i in my_range:
print(i)
0
1
2
3
4
5
6
7
8
9