LoginSignup
20
11

More than 3 years have passed since last update.

Python 3.7 ではGeneretor で StopIteration を使うと RuntimeError になる

Posted at

次のコードは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
20
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
11