# 다음 코드는 이런 동작 방식을 보여준다.
class MyError(Exception):
pass
def my_generator():
yield 1
yield 2
yield 3
it = my_generator()
print(next(it)) # 1을 내놓음
print(next(it)) # 2를 내놓음
# 오류가 나는 부분. 오류를 보고 싶으면 커멘트를 해제할것
print(it.throw(MyError('test error')))
#2번째 다음에 3을 부르기 전에 Myerror라는 부분이 있어야하는데 없어서 error가 발생하고 다음 순서인 3으로 넘어가지못하고
# 제너레이터는 2까지만 실행이 되어버린것?
1
2
MyError Traceback (most recent call last)
in
13 print(next(it)) # 2를 내놓음
14 # 오류가 나는 부분. 오류를 보고 싶으면 커멘트를 해제할것
---> 15 print(it.throw(MyError('test error')))
16
17 #2번째 다음에 3을 부르기 전에 Myerror라는 부분이 있어야하는데 없어서 error가 발생하고 다음 순서인 3으로 넘어가지못하고
in my_generator()
5 def my_generator():
6 yield 1
----> 7 yield 2
8 yield 3
9
MyError: test error
def my_generator():
yield 1
try:
yield 2 #2를 호출하는데 다음 호출시 yield2는 사용 불가로 except를 실행하게댐
except MyError:
print('MyError 발생!')
else:
yield 3
yield 4
it = my_generator()
print(next(it)) # 1을 내놓음
print(next(it)) # 2를 내놓음
print(it.throw(MyError('test error')))
#2까지는 무리업이 되고
#다음 순서인 myerror가 발생하고 except가 에러가 안났기 때문에 else는 넘어가고 바로 yield4 실행?
1
2
MyError 발생!
4
# ex) 작성하는 프로그램에 간헐적으로 재설정할 수 있는 타이머가 필요
# 다음은 throw 메서드에 의존하는 제너레이터를 통해 타이머를 구현하는 코드다.
# yield식에서 Reset 예외가 발생할 때마다 카운터가 period로 재설정 된다.
class Reset(Exception):
pass
def timer(period):
current = period
while current:
current -= 1
try:
yield current
except Reset:
current = period
RESETS = [
False, False, False, True, False, True, False,
False, False, False, False, False, False, False]
#true가 나오면 period를 reset시켜서 다시 3부터 시작
#이후 계속되다가 제너레이터가 끝나면 break
def check_for_reset():
# 외부 이벤트를 폴링한다
return RESETS.pop(0) #하나씩 끄집어내고 원래 변수에서는 삭제
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 틱 남음
3 틱 남음
2 틱 남음
3 틱 남음
2 틱 남음
1 틱 남음
0 틱 남음
위 코드는 읽기가 어렵다.
각 내포 단계마다 StopIteration 예외를 잡아내거나 throw를 할지, next나 announce를 호출할지 결정하는데 , 이로인해 잡음이많다.
이 기능을 구현하는 더 단순한 방법은 이터러블 컨테이너 객체를 사용해 상태가 있는 클로저를 정의하는 것이다.
이러한 클래스를 사용해 timet 제너레이터를 재정의한 코드는 다음과 같다.
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
이제 run 메서드에서는 for를 사용해 훨씬 단순하게 이터레이션을 수행할 수 있고, 내포 수준이 줄어들어 코드가 훨씬 읽기 쉽다.
RESETS = [
False, False, False, True, False, True, False,
False, False, False, False, False, False, False]
def run():
timer = Timer(4)
for current in timer:
if check_for_reset():
timer.reset()
announce(current)
run()
3 틱 남음
2 틱 남음
1 틱 남음
0 틱 남음
3 틱 남음
2 틱 남음
3 틱 남음
2 틱 남음
1 틱 남음
0 틱 남음