↓ 본문으로 건너뛰기
Python Generator (a.k.a. 'yield')
  1. 글/

Python Generator (a.k.a. 'yield')

작성자
Kim Won Tae
고객의 현장에서 업무 구조와 환경, 그리고 잠재된 불편함을 분석하고, 사용자 경험을 개선할 수 있는 도메인 특화 AI 서비스 및 에이전트를 개발합니다.

오늘은 파이썬의 generator 개념을 한번 정리해보도록 하겠다.

Python Generator란?
#

먼저 파이썬에서 generator란, 반복자(iterator)와 유사한 개념으로, 한번에 **‘하나’**의 항목을 생성하는 객체를 의미한다.

일반함수와는 다르게, **‘yield’**문을 사용해서 값을 반환하는데, 

하나의 값을 반환 후 함수의 실행상태를 유지하며, 필요할때마다 값을 생성할 수 있는데, 이전에 생성한 다음부터 이어서

생성하는 특징이 있다.

먼저, yield문을 활용한 간단한 파이썬 제너레이터 예시를 살펴 보자.

def simple_generator():
    yield 1
    yield 2
    yield 3

# 제너레이터 생성
gen = simple_generator()

# 제너레이터에서 값을 하나씩 가져오기
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3

위 예시를 보면 먼저 ‘simple_generator’함수는 제너레이터를 정의하고있다. 

이 함수는 ‘yield’문을 통해 세개의 숫자를 순차적으로 생성하는데,

**‘next()’**함수를 호출할때마다, 제너레이터는 이전 출력값의 ‘다음’ 출력값을 반환하고, 

반환 즉시, 그 위치에서 실행을 일시중지한다.

마찬가지로, 다음 ‘next()’ 호출시에는 일시 중지된 위치부터 다시 실행을 시작한다.

원리와 동작은 좀 이해가 가는가?

그럼, 이제 제너레이터는 왜 사용하고, 어떤 케이스에서 활용되는지 궁금하다.

아래에서 파이썬 제너레이터가 사용되는 몇가지 예시를 살펴보자.

#

CASE 1) 데이터 스트리밍 및 파일처리
#

먼저, 제너레이터의 가장 큰 특징인, 한번에 하나의 출력만 수행한다는 점을 활용해서,

큰 데이터셋을 처리할떄, 전체 데이터를 한번에 메모리에 로드하는 대신, 필요한 부분만 순차적으로 처리할 수 있다.

아래 예시코드를 보자.

def read_large_file(file_name):
    with open(file_name, 'r') as file:
        for line in file:
            yield line

# 파일에서 한 줄씩 읽기
for line in read_large_file('large_file.txt'):
    print(line)

위 코드에서 ‘read_large_file’함수에서는 로드한 파일에 대해, ‘yield’문을 통해 한줄씩 출력한다.

덕분에 한번에 데이터를 로드하지않고, 필요할때마다 한줄씩 꺼내서 쓸 수 있다.

비슷한 예를 한가지 더 살펴보자.

def read_file_in_chunks(file_name, chunk_size=1024):
    with open(file_name, 'r') as file:
        while True:
            chunk = file.read(chunk_size)
            if not chunk:
                break
            yield chunk

# 파일을 청크 단위로 읽기
for chunk in read_file_in_chunks('large_file.txt'):
    print(chunk)

비슷하게, 파일을 chunk단위로 읽어서, 필요한 만큼 반복적으로 불러올 수 있다.

예를들어, 대용량의 로그파일을 읽어와 특정 키워드를 체크해야한다고 했을때, 

전체파일을 읽어와 분석한다면 메모리가 크게 사용되어 비효율적이다.

제너레이터를 사용하면, 한번에 하나의 line씩 불러와 진행할 수 있기때문에, 메모리 사용을 최적화 하는데 유용하다.

CASE 2) 무한 시퀀스 생성
#

무한으로 시퀀스를 생성하는 함수에서 yield문을 통해, 한번에 하나의 시퀀스만 출력하도록 구성하면,

필요한 시점에 이전 출력 이후의 시퀀스를 계속해서 출력받아 사용할 수 있다.

def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 피보나치 수열의 처음 10개 숫자 출력
fib = fibonacci()
for _ in range(10):
    print(next(fib))

위는 피보나치수열을 생성하는 간단한 함수이다. 

이 함수를 통해 생성되는 피보나치 수열의 원소들을 순차적으로 필요한 시점에, 사용자가 정한 만큼 계속 출력해낼 수 있다.

아마도 데이터가 적재되는 시점에, 이에 대한 unique한 시퀀스가 필요할때 활용될 수 있는 방법이지 않을까 생각해본다.

CASE 3) 비동기 프로그래밍
#

# 비동기 프로그래밍에는 asyncio 라이브러리와 같은 추가적인 도구가 필요하며,
# 제너레이터를 사용하여 비동기 작업을 관리할 수 있다.
# 예시:

async def async_generator():
    for i in range(10):
        await asyncio.sleep(1)
        yield i

마지막으로 비동기 프로그래밍에서도 제너레이터가 유용하게 사용될 수 있는데,

‘yield’문을 통해, 비동기 함수내에서, 함수 내 정의된 기능을 

필요한 시점에 계속해서 출력받을 수 있도록 활용할 수 있다.

#

마치며
#

오늘 알아본 python 제너레이터를 요약해보면,

사용자가 “**원하는 시점에 연속적으로 출력받을 수 있는 생성자의 기능”**으로 정의할 수 있을 것 같다.

iteration에서 한번에 하나의 출력만 하며, 출력시점을 사용자가 선택할 수 있다는 점에서 

특히, 대용량의 파일 관리시에 유용하게 활용될 수 있는 기능으로 보여진다.

#

Reference
#

[39. Generator(제네레이터)

1. Generator란? - generator : iterator를 생성해주는 함수, 함수안에 yield 키워드를 사용함 - genrator 특징 - iterab…
#

wikidocs.net](https://wikidocs.net/16069)