まとめ
- 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 に続きます。