제너레이터 안에서 Exception을 다시 던질 수 있는 throw 메서드가 있다.
class MyError(Exception):
pass
def my_generator():
yield 1
yield 2
yield 3
it = my_generator()
print(next(it))
print(next(it))
print(it.throw(MyError('test error')))
1 2
--------------------------------------------------------------------------- MyError Traceback (most recent call last) <ipython-input-6-5000f6e47c06> in <module> 2 print(next(it)) 3 print(next(it)) ----> 4 print(it.throw(MyError('test error'))) <ipython-input-5-dbcd45bc83be> in my_generator() 1 def my_generator(): 2 yield 1 ----> 3 yield 2 4 yield 3 MyError: test error
throw를 호출해 제너레이터에 예외를 주입해도, 제너레이터는 try/except 복합문을 사용해 마지막으로 실행된 yield 문을 둘러쌈으로써 이 예외를 잡아낼 수 있다.
def my_generator():
yield 1
try:
yield 2
except MyError:
print('MyError 발생!')
else:
yield 3
yield 4
it = my_generator()
print(next(it))
print(next(it))
print(it.throw(MyError('test error')))
1 2 MyError 발생! 4
이 기능은 제너레이터와 제너레이터를 호출하는 쪽 사이에 양방향 통신 수단을 제공한다.
class Reset(Exception):
pass
def timer(period):
current = period
while current:
current -= 1
try:
yield current
except Reset:
current = period
yield 식에서 Reset 예외가 발생할 때마다 카운터가 period로 재설정된다.
def check_for_reset():
pass
def announce(remaining):
print(f'{remaining} 틱 남음')
def run():
it = timer(4)
while True:
try:
if check_for_reset():
current = it.throw(Reset())
else:
current = next(it)
except StopIteration:
break
else:
announce(current)
run()
3 틱 남음 2 틱 남음 1 틱 남음 0 틱 남음
class Timer:
def __init__(self, period):
self.current = period
self.period = period
def reset(self):
self.current = self.period
def __iter__(self):
while self.current:
self.current -= 1
yield self.current
def run():
timer = Timer(4)
for current in timer:
if check_for_reset():
timer.reset()
announce(current)
run()
3 틱 남음 2 틱 남음 1 틱 남음 0 틱 남음