41.2 코루틴 바깥으로 값 전달하기
지금까지 코루틴 안에 값을 보내기만 했는데 이번에는 코루틴에서 바깥으로 값을 전달해보겠습니다. 다음과 같이 (yield 변수) 형식으로 yield에 변수를 지정한 뒤 괄호로 묶어주면 값을 받아오면서 바깥으로 값을 전달합니다. 그리고 yield를 사용하여 바깥으로 전달한 값은 next 함수(__next__ 메서드)와 send 메서드의 반환값으로 나옵니다.
- 변수 = (yield 변수)
- 변수 = next(코루틴객체)
- 변수 = 코루틴객체.send(값)
그럼 코루틴에 숫자를 보내고, 코루틴은 받은 숫자를 누적해서 바깥에 전달해보겠습니다.
coroutine_producer_consumer.py
def sum_coroutine(): total = 0 while True: x = (yield total) # 코루틴 바깥에서 값을 받아오면서 바깥으로 값을 전달 total += x co = sum_coroutine() print(next(co)) # 0: 코루틴 안의 yield까지 코드를 실행하고 코루틴에서 나온 값 출력 print(co.send(1)) # 1: 코루틴에 숫자 1을 보내고 코루틴에서 나온 값 출력 print(co.send(2)) # 3: 코루틴에 숫자 2를 보내고 코루틴에서 나온 값 출력 print(co.send(3)) # 6: 코루틴에 숫자 3을 보내고 코루틴에서 나온 값 출력
실행 결과
0 1 3 6
코루틴에서 값을 누적할 변수 total를 만들고 0을 할당합니다. 그리고 x = (yield total)과 같이 값을 받아오면서 바깥으로 값을 전달하도록 만듭니다. 즉, 바깥에서 send가 보낸 값은 x에 저장되고, 코루틴 바깥으로 보낼 값은 total입니다. 그다음에 total += x와 같이 받은 값을 누적해줍니다.
def sum_coroutine(): total = 0 while True: x = (yield total) # 코루틴 바깥에서 값을 받아오면서 바깥으로 값을 전달 total += x
코루틴 바깥에서는 co = sum_coroutine()과 같이 코루틴 객체를 생성한 뒤 next(co)로 코루틴 안의 코드를 최초로 실행하여 yield까지 코드를 실행하고, print로 next(co)에서 반환된 값을 출력합니다. 그다음에 co.send로 숫자 1, 2, 3을 보내고, print로 co.send에서 반환된 값을 출력합니다.
co = sum_coroutine() print(next(co)) # 0: 코루틴 안의 yield까지 코드를 실행하고 코루틴에서 나온 값 출력 print(co.send(1)) # 1: 코루틴에 숫자 1을 보내고 코루틴에서 나온 값 출력 print(co.send(2)) # 3: 코루틴에 숫자 2를 보내고 코루틴에서 나온 값 출력 print(co.send(3)) # 6: 코루틴에 숫자 3을 보내고 코루틴에서 나온 값 출력
참고로 next와 send의 차이를 살펴보면 next는 코루틴의 코드를 실행하지만 값을 보내지 않을 때 사용하고, send는 값을 보내면서 코루틴의 코드를 실행할 때 사용합니다.
이 코루틴의 동작 과정을 그림으로 살펴보겠습니다.
먼저 next(co)로 코루틴의 코드를 최초로 실행하면 x = (yield total)의 yield에서 total을 메인 루틴으로 전달하고 대기합니다. 그다음에 메인 루틴에서 print(next(co))와 같이 코루틴에서 나온 값을 출력합니다. 여기서는 total에 0이 들어있으므로 0을 받아와서 출력합니다.
그리고 co.send(1)로 1을 보내면 코루틴은 대기 상태에서 풀리고 x = (yield total)의 x = 부분이 실행된 뒤 total += x로 숫자를 누적합니다. 이 코루틴은 while True:로 반복하는 구조이므로 다시 x = (yield total)의 yield에서 total을 메인 루틴으로 전달하고 대기합니다. 그다음에 메인 루틴에서 print(co.send(1))과 같이 코루틴에서 나온 값을 출력합니다. 여기서는 total에 1이 들어있으므로 1을 받아와서 출력합니다.
이런 과정으로 (yield total)이 바깥으로 전달한 값을 next와 send의 반환값으로 받고, send가 보낸 값을 x = (yield total)의 x가 받게 됩니다.
여기서는 yield를 사용하여 코루틴 바깥으로 값을 전달하면 next와 send의 반환값으로 받는다는 점만 기억하면 됩니다.
마지막으로 제너레이터와 코루틴의 차이점을 정리해보겠습니다.
- 제너레이터는 next 함수(__next__ 메서드)를 반복 호출하여 값을 얻어내는 방식
- 코루틴은 next 함수(__next__ 메서드)를 한 번만 호출한 뒤 send로 값을 주고 받는 방식
코루틴은 초보자가 처음부터 작성하기가 힘듭니다. 따라서 다른 사람이 만든 소스 코드(GitHub에 공개된 소스 코드 등)를 참고하여 학습하고, 조금씩 수정하면서 원하는 결과를 얻어내면 됩니다.
값을 보내지 않으면서 코루틴의 코드를 실행할 때는 next 함수(__next__ 메서드)만 사용하면 됩니다. 잘 생각해보면 이 방식이 일반적인 제너레이터입니다.