본문 바로가기

갈아먹는 파이썬 [1] generator와 yield

들어가며

파이썬을 주로 사용하시는 분들이라면 한번쯤 generator에 대해서 들어보셨을 겁니다.

하지만 딱이 몰라도 코딩하는데 큰 지장이 없어서 그냥 지나치신 분들이 많으실 것으로 생각합니다. (저도 그랬거든요!)

 

하지만 데이터의 양이 많아지고, 메모리 사용량을 최적화 해야하는 상황이 온다면

generator의 사용은 필수적입니다.

그래서 오늘은 파이썬 generator가 무엇인지, 그리고 이를 만들어주는 yield란 무엇인지 알아보겠습니다.

 

이 포스팅은 직접 작성한 주피터 노트북에 기반합니다. 스타 한번씩 부탁드려요 ㅎㅎ

https://github.com/yeomko22/python_study

 

yeomko22/python_study

Python study in part of HR-bigdata course of Yonsei Univ Fall 2019. - yeomko22/python_study

github.com

generator란?

파이썬 제너레이터는 메모리를 효율적으로 사용하면서 반복을 수행하도록 돕는 객체입니다.
제너레이터가 무엇인지 감을 잡기 위해 먼저 다음과 같은 문제를 상상해보겠습니다.
문제: 특정한 길이의 숫자 배열이 주어졌을 때, 이를 제곱한 수들을 담은 배열을 출력하라

이를 list를 활용하여 풀면 다음과 같이 풀 수 있습니다.

 

list를 이용하여 쉽게 문제를 풀 수 있는 것을 보았습니다.
하지만 숫자의 개수가 1억개가 된다면 어떻게 될까요? 아마도 result에는 1억개의 제곱된 숫자가 저장한 다음 출력해야 합니다.

Python Generator는 이런 방식의 반복이 비효율적이다고 생각하여 만들어졌습니다.

즉, 대용량 반복을 수행해야할 때, 메모리를 더욱 효율적으로

사용하기 위한 도구가 Generator입니다.


우선, generator를 사용한 방식으로 square 함수를 만들어보겠습니다.

결과를 출력해보면 배열이 아니라 generator라는 객체가 돌아온 것을 볼 수 있습니다.
그리고 square 함수를 보면 return 대신에 yield라는 구문을 사용한 것을 볼 수 있습니다.
이 차이를 이해하기 위해서는 먼저 return과 yield의 차이를 알아야합니다.

return과 yield의 차이

먼저 return을 사용해서 임의의 수를 반환하는 함수입니다.
임의의 수를 생성하고, 이를 10회 반복하여 return 하도록 하였습니다.

하지만 return이 호출되면 반복을 멈추고, 수를 반환하며 따라서 그 뒤에 hello가 출력되지 않습니다.
그리고 이 때 만들었던 임의의 수는 메모리에서 할당 해제되어 다시 호출할 수 없습니다.

 

반면 같은 기능을 하는 함수를 return 대신에 yield를 사용하여 작성해보았습니다.

yield가 호출되면 함수는 그 시점에서 일시 정지합니다.
그리고 그 시점에 함수 안에 선언되어 있는 변수들을 기억합니다.
next()를 통해 실행되면 yield 바로 다음 라인부터 다시 실행을 이어나갑니다.

즉, yield를 호출하면 원하는 값을 리턴하며, 실행 흐름을 일시 정지하여

함수를 재활용할 수 있는 상태로 만듭니다.

 

yield와 return의 차이가 어느 정도 이해가셨나요?
이제 다시 generator로 돌아오겠습니다. next 함수를 사용하지 않고도 for문에서 generator 계산 결과를 가져올 수 있습니다.

generator expression

어때요, 이제 generator가 어떤 역할을 하고, 어떻게 사용하는지 감이 오시나요?
파이썬에서는 굳이 yield를 포함한 함수를 만들기 않고도 쉽게 generator를 사용할 수 있는
generator expression을 제공합니다.

마치며

사실 제너레이터는 성능 최적화가 필요한 상황에서 요긴하게 사용되는 것이므로
평상시 개발할 때 필요성을 느끼지 못하는 경우가 많습니다.

 

하지만 대용량 데이터를 처리하거나, 알고리즘 문제를 푸는 등 성능이 중요한 상황이 오게 됩니다.

(파이썬 관련 인터뷰 단골 질문이기도 하죠 ㅎㅎ)
그럴때 꼭 Generator를 잊지 말고 사용하면 좋을 듯 합니다. 감사합니다!