LoginSignup
6
7

More than 5 years have passed since last update.

Python の Iterator と Generator

Posted at

まとめ

  • Iterator とは、__iter____next__ を持つオブジェクト。for などで繰り返しに使える。
  • Generator function とは、yield を含む関数。Generator を返す。
  • Generator とは、Iterator の一種。send() や throw() など拡張機能もある。

Iterator

まずイテレータの復習。__iter____next__ を持つオブジェクトをイテレータと呼び、for などで繰り返しに使える。

# 1 から max までの数を数えるカウンターをイテレータとして作った
class Counter():

    def __init__(self, max):
        self.count = 0
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        self.count += 1
        if self.count <= self.max:
            return self.count
        raise StopIteration()

# 1 から 3 まで for で数える
for i in Counter(3):
    print(i)

# next(iterator, default) はイテレータの次の値を返す。無ければデフォルトを返す。
counter = Counter(3)
print(next(counter, '終わり'))
print(next(counter, '終わり'))
print(next(counter, '終わり'))
print(next(counter, '終わり'))

実行結果

1
2
3
1
2
3
終わり

Generator

Yield 文を使うと、クラス構文を使わずにイテレータを作る事が出来る。yield を含む関数をジェネレータ関数と呼ぶ。ジェネレータ関数は return を含まないのにジェネレータと呼ぶオブジェクトを返す。ジェネレータはイテレータとして使える。yield 文でイテレータとしての結果を返す。

# 1 から max までの数を数えるカウンターをジェネレータで作った
def counter_simple(max=None):
    count = 0
    while count < max:
        count += 1
        next = yield count

for i in counter_simple(3):
    print(i)

実行結果

1
2
3

ジェネレータにはイテレータに加えていろいろ機能がある。

  • generator.send() で値を渡す。渡した値は yield の戻り値となる。
  • generator.throw() で例外を投げられる。
  • generator.close() で中断出来る。
# 1 から max までの数を数えるカウンター高級版
def counter_rich(max=None):
    count = 0
    try:
        while count < max:
            count += 1
            try:
                next = yield count
                if next != None:
                    count = next
            except Exception as e:
                print(f'例外「{e}」がやってきた!')
    finally:
        print('終了します')

print('100 まで数えるカウンター')
counter = counter_rich(100)
print(next(counter))
print(next(counter))
print('counter に 5 を送ってスキップ')
print(counter.send(5))
print(next(counter))
counter.throw(Exception('ちょっと待って'))
print(next(counter))
print(next(counter))
print('100 に行く前に中断')
counter.close()
print(next(counter))

実行結果

100 まで数えるカウンター
1
2
counter に 5 を送ってスキップ
6
7
例外「ちょっと待って」がやってきた!
9
10
100 に行く前に中断
終了します
Traceback (most recent call last):
  File "generator.py", line 38, in <module>
    print(next(counter))
StopIteration

asyncio に続きます。

6
7
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
6
7