오늘은 파이썬의 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
'DEVELOP_NOTE > Python' 카테고리의 다른 글
Garbage Collection(가비지 컬렉션, GC)은 어떻게 동작할까? (0) | 2024.02.22 |
---|---|
Python Decorator @ 사용방법 완벽 이해하기! (0) | 2024.02.07 |
[REFACTORING] dictionary에 'key' 존재 유무에 따른 데이터 채우기 (0) | 2024.02.05 |