제너레이터 안에서 throw 호출
yield로 평소처럼 실행
throw가 제공한 Exception다시 던진다.
#throw 메소드에 의존하는 제너레이터 타이머
class Reset(Exception):
pass
def timer(period):
current = period
while current:
current -=1
try:
yield current
except Reset:
current = period
#타이머 코드
def check_for_reset():
#외부 이벤트 폴링
...
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()
작동은 잘하지만 가독성이 너무 떨어진다.
각 내포 단계별로 throw or 호출로 결정되는데 코드 잡음이 많다.
해결책: iterlabel class 사용
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()
throw메서드를 사용하면 제너레이터가 마지막으로 실행한 yield 식의 위치에서 예외가 다시 발생할 수 있다
throw를 사용하면 가독성이 나빠지게 되어서 예외를 잡아내고 다시 발생시키는데 준비 코드가 필요하고 내포 단계가 깊어진다.
제너레이터에서 예외적인 동작을 제공하는 더 나은 법은 iter메서드를 구현하는 클래스를 사용해서 예외적인 경우 상태 전이