-
[코딩도장] day27. 파이썬 코루틴 - next, send, yieldIT/파이썬 2020. 9. 21. 23:44
■ 들어가기
- 파이썬 코딩 도장 (남재윤/길벗). 을 공부하며 정리하는 블로그
▶ Unit 41. 코루틴 사용하기
- 41.1 코루틴에 값 보내기
- 41.2 코루틴 바깥으로 값 전달하기
- 41.3 코루틴을 종료하고 예외 처리하기
- 41.4 하위 코루틴의 반환값 가져오기
0. 들어가기
- 일반적으로 함수를 호출한 뒤 함수가 끝나면 현재 코드로 다시 돌아옴
- 예시 : calc 함수에서 add 함수를 호출한 뒤 다시 calc 함수로 돌아옴>>> def add(a, b) :
c = a + b
print(c)
print('add 함수')
>>> def calc() :
add(1, 2)
print('calc 함수')
>>> calc()
3
add 함수
calc 함수- calc 함수와 add 함수와의 관계
calc 함수 : 메인 루틴(main routine), add 함수 : 서브 루틴(sub routine)
- 메인 루틴에서 서브 루틴을 호출하면 서브 루틴 수행 후 다시 메인 루틴으로 돌아가며
이 때 서브 루틴 수행 시간 동안 메인 루틴은 대기함- 코루틴(coroutine, cooperative routine) : 서로 협력한다는 의미로, 메인 루틴과 서브 루틴처럼 종속된 관계가 아니라 서로 대등한 관계임
- 특정 시점에 상대방의 코드를 실행- 코루틴은 함수가 종료되지 않은 상태에서 메인 루틴의 코드를 실행한 뒤 다시 돌아와서 코루틴의 코드를 실행
- 코루틴이 종료되지 않았기에 코루틴의 내용도 계속 유지
- 일반 함수는 호출하면 코드를 한 번만 실행 가능하지만, 코루틴은 코드를 여러 번 실행 가능
(함수의 코드를 실행하는 지점을 진입점(entry point)라 부르며, 코루틴은 진입점이 여러 개인 함수이다)>> 41.1 코루틴에 값 보내기 <<
- 코루틴은 제너레이터의 특별한 형태
- 제너레이터는 yield로 값을 발생시켰지만, 코루틴은 yield로 값을 받아 옴
( 코루틴에 값을 보내면서 코드 실행 시에는 send 메서드 사용 )
- 사용법코루틴객체.send(값)
변수 = (yield)
소스 (coroutine_consumer.py) 결과 def number_coroutine() :
while True : # 코루틴 계속 유지위해 무한 루프 사용
x = (yield) # 코루틴 바깥에서 값을 받아옴
print(x)
co = number_coroutine()
next(co) # 코루틴 안의 yield까지 코드 실행
co.send(1)
co.send(2)
co.send(3)1
2
3- next 함수로 코루틴의 코드를 최초 실행하고, send 메서드로 코루틴에 값을 보내면서 대기하고 있던 코루틴의 코드를 다시 실행
>> 41.2 코루틴 바깥으로 값 전달하기 <<
- 예제 : 코루틴에 숫자를 보내고, 코루틴은 받은 숫자를 누적해서 바깥에 전달하기
소스 (coroutine_producer_consumer.py) 결과 def sum_coroutine() :
total = 0
while True :
x = (yield total) # 코루틴 외부에서 값을 받으면서 외부로 값을 전달
total += x
co = sum_coroutine()
print(next(co)) # 코루틴 안의 yield까지 코드를 실행하고 코루틴에서 나온 값 출력
print(co.send(1)) # 코루틴에 숫자 1을 보내고 코루틴에서 나온 값 출력
print(co.send(2)) # 코루틴에 숫자 2를 보내고 코루틴에서 나온 값 출력
print(co.send(3)) # 코루틴에 숫자 3을 보내고 코루틴에서 나온 값 출력0
1
3
6- 외부에서 send가 보낸 값은 함수 내부 x에 저장되며, 코루틴 외부로 보낼 값은 total이 된다.
- 코루틴 외부에서는 "co = sum_coroutine()" 로 코루틴 객체 생성
- "next(co)"로 코루틴 안의 코드를 최초로 실행하여 yield까지 코드를 실행하여 print로 반환된 값 출력
- "co.send"로 숫자 1, 2, 3을 보내고 print로 반환된 값 출력
- next vs send 차이점??
next : 코루틴의 코드를 실행하지만 값을 (외부로) 보내지 않을 때 사용
send : 코루틴의 코드를 실행하고 값을 (외부로) 보낼 경우 사용- 제너레이터 vs 코루틴 차이점??
제너레이터 : next 함수(__next__ 메서드)를 반복 호출하여 값을 얻어내는 방식
코루틴 : next 함수(__next__ 메서드)를 한 번만 호출한 뒤 send로 값을 주고받는 방식>> 41.3 코루틴을 종료하고 예외 처리하기 <<
- 일반적으로 코루틴은 상태 유지를 위해 "while True : " 를 사용해서 무한 루프로 동작하지만
- 코루틴을 강제 종료하고 싶다면 close 메서드를 사용!
- 사용법 : 코루틴객체.close()
소스 (coroutine_close.py) 결과 def number_coroutine() :
while True :
x = (yield)
print(x, end=' ')
co = number_coroutine()
next(co)
for i in range(20) :
co.send(i)
co.close()0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 1. GeneratorExit 예외 처리하기
- 코루틴 객체에서 close 메서드 호출하면 코루틴이 종료될 때 GeneratorExit 예외가 발생하며,
- 이를통해 코루틴의 종료 시점 알 수 있음
소스 (coroutine_generator_exit.py) 결과 def number_coroutine() :
try :
while True :
x = (yield)
print(x, end=' ')
except GeneratorExit : # 코루틴 종료 시 GeneratorExit 예외 발생
print()
print('코루틴 종료')
co = number_coroutine()
next(co)
for i in range(20) :
co.send(i)
co.close()0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
코루틴 종료2. 코루틴 안에 예외 발생시키기
- 코루틴 안에 특정 예외 발생시킬 때는 throw 메서드를 사용
- throw 메서드에 지정한 에러 메시지는 except as의 변수에 들어감
- 사용법 : 코루틴객체.throw(예외이름, 에러메시지)
소스 (coroutine_throw.py) 결과 def sum_coroutine() :
try :
total = 0
while True :
x = (yield)
total += x
except RuntimeError as e :
print(e)
yield total # 코루틴 바깥으로 값 전달
co = sum_coroutine()
next(co)
for i in range(20) :
co.send(i)
print(co.throw(RuntimeError, '예외로 코루틴 끝내기'))예외로 코루틴 끝내기
190√ 그런데 이 기능은 언제 쓰는거지??;;;
>> 41.4 하위 코루틴의 반환값 가져오기 <<
- 제너레이터에서 "yield from"을 사용하면 값을 바깥으로 여러 번 전달 (40.3 참고)
- 다만, 코루틴에서 "yield from"은 해당 코루틴에서 return 으로 반환한 값을 가져온다 (단, 파이썬 3.3버전 이상)
- 사용법
변수 = yield from 코루틴()
소스 (coroutine_yield_from.py) 결과 def accumulate() :
total = 0
while True :
x = (yield) # 코루틴 바깥에서 값을 받아옴
if x is None : # 받아온 값이 None이면
return total # 합계 total을 반환
total += x
def sum_coroutine() :
while True :
total = yield from accumulate() # accumulate의 반환값을 가져옴
print(total)
co = sum_coroutine()
next(co)
for i in range(1, 11) : # 1 ~ 10까지 반복
co.send(i) # 코루틴 accumulate에 숫자를 보냄
co.send(None) # 코루틴 accumulate에 None을 보내 숫자 누적 종료
for i in range(1, 101) : # 1 ~ 100까지 반복
co.send(i) # 코루틴 accumulate에 숫자를 보냄
co.send(None) # 코루틴 accumulate에 None을 보내 숫자 누적 종료55
5050- sum_coroutine 메서드에서 "while True : "로 무한루프 수행 중이므로,
- print(total) 수행 수 다시 "yield from accumulate()" 로 accumulate를 실행
1. StopIteration 예외 발생시키기
- 코루틴도 제너레이터이므로 return을 사용하면 StopIteration 예외가 발생
- 따라서 코루틴에서 "return 값" 은 "raise StopIteration(값)" 처럼 사용 가능하며, "yield from" 으로 값을 가져올 수 있음
- 사용법 : raise StopIteration(값)
소스 (coroutine_stopiteration.py) 결과 def accumulate() :
total = 0
while True :
x = (yield)
if x is None :
raise StopIteration(total)
total += x
def sum_coroutine() :
while True :
total = yield from accumulate()
print(total)
co = sum_coroutine()
next(co)
for i in range(1, 11) :
co.send(i)
co.send(None)
for i in range(1, 101) :
co.send(i)
co.send(None)55
5050'IT > 파이썬' 카테고리의 다른 글
[코딩도장] day29. 파이썬 데코레이터(2/2) (0) 2020.09.26 [코딩도장] day28. 파이썬 데코레이터(1/2) - @데코레이터, def데코레이터 (0) 2020.09.22 [코딩도장] day27. 파이썬 제너레이터 사용하기 - yield (0) 2020.09.21 [코딩도장] day27. 파이썬 이터레이터 사용하기 - __iter__, __next__, __getitem__ (0) 2020.09.21 [코딩도장] day26. 파이썬 예외 처리 사용하기 - try except, else, finally (0) 2020.09.20