본문 바로가기

DEVELOP_NOTE/Python

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

오늘은 파이썬의 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