-
제너레이터(Generator) 활용 예제python 2026. 1. 11. 23:51
코딩을 하다 보면 데이터가 너무 커서 MemoryError가 발생하거나, 무한히 반복되는 데이터를 다뤄야 할 때가 있죠. 이럴 때 리스트(List) 대신 제너레이터를 사용하면 메모리 효율을 극적으로 높일 수 있습니다.
제너레이터(Generator)란?
제너레이터는 이터레이터(Iterator)를 생성하는 함수입니다.
쉽게 비유하자면, 리스트(List)가 이미 만들어진 음식 100접시를 식탁에 한 번에 올려두는 것이라면, 제너레이터는 주문이 들어올 때마다 요리사가 음식을 하나씩 만들어 내어주는 것과 같습니다.
이를 지연 평가(Lazy Evaluation)라고 합니다. 데이터가 필요할 때(호출될 때) 비로소 생성하기 때문에 메모리를 거의 쓰지 않습니다.
핵심 키워드: yield
일반 함수는 return을 만나면 값을 반환하고 완전히 종료되지만, 제너레이터는 yield를 사용합니다.
- return: "값 가져가! 난 이제 퇴근할게." (함수 종료)
- yield: "일단 이 값 가져가고, 난 여기서 잠깐 대기할게." (일시 정지)
def number_generator(): yield 1 # 1을 주고 멈춤 yield 2 # 다시 호출되면 여기서부터 실행, 2를 주고 멈춤 yield 3 # 3을 주고 멈춤 gen = number_generator() print(next(gen)) # 1 print(next(gen)) # 2 print(next(gen)) # 3
실전 예제
엄청난 메모리 차이 (리스트 vs 제너레이터)
숫자 100만 개를 만든다고 가정해 봅시다.
- 리스트 컴프리헨션 []: 100만 개를 메모리에 다 올립니다.
- 제너레이터 표현식 (): 생성 규칙만 기억합니다.
import sys # 리스트: 대괄호 [] 사용 big_list = [i for i in range(1000000)] # 제너레이터: 소괄호 () 사용 big_gen = (i for i in range(1000000)) print(f"리스트 메모리: {sys.getsizeof(big_list)} bytes") print(f"제너레이터 메모리: {sys.getsizeof(big_gen)} bytes") # [결과] # 리스트 메모리: 8,448,728 bytes (약 8MB) # 제너레이터 메모리: 112 bytes (압도적으로 작음!)데이터가 1억 개, 10억 개로 늘어나도 제너레이터의 메모리 사용량은 변하지 않습니다.
대용량 파일 처리 (Log Analysis)
수 기가바이트(GB)가 넘는 로그 파일을 분석해야 한다면? readlines()로 한 번에 읽으면 메모리가 터집니다. 제너레이터를 사용해 한 줄씩 읽어야 합니다.
def read_large_file(filename): with open(filename, 'r') as f: for line in f: yield line.strip() # 한 줄 읽고 대기, 다음 호출 때 다음 줄 읽음 # 파일 크기가 100GB라도 메모리 걱정 없음 log_gen = read_large_file('server_log.txt') for log in log_gen: if "ERROR" in log: print(f"에러 발견: {log}")무한 시퀀스 (Infinite Sequence)
끝이 없는 데이터(센서 데이터, 주식 시세 등)는 리스트에 담을 수 없습니다. 하지만 제너레이터는 while True를 써도 프로그램이 멈추지 않습니다. yield가 흐름을 제어하기 때문이죠.
def infinite_fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b fibo = infinite_fibonacci() for _ in range(5): print(next(fibo), end=' ') # 출력: 0 1 1 2 3데이터 파이프라인 (Chaining)
제너레이터끼리 연결하면 복잡한 데이터 처리 과정을 레고 블록 조립하듯 깔끔하게 짤 수 있습니다.
[과정: 랜덤 숫자 생성 -> 짝수만 필터링 -> 제곱하기]
import random def random_stream(): while True: yield random.randint(1, 100) def even_filter(nums): for n in nums: if n % 2 == 0: yield n def square_mapper(nums): for n in nums: yield n * n # 파이프라인 조립 (실행은 아직 안 됨) data = random_stream() evens = even_filter(data) squared = square_mapper(evens) # 수도꼭지를 트는 순간 데이터가 흐름 for i, value in enumerate(squared): print(value) if i == 4: break # 5개만 출력하고 종료'python' 카테고리의 다른 글
모듈, 패키지, 라이브러리, 그리고 프레임워크 (1) 2026.01.13 가변 인자와 Packing/Unpacking의 원리 (0) 2026.01.13 Closure, 도대체 왜 쓰는 걸까? (0) 2026.01.09 Iterable ? Iterator? Generator? (0) 2026.01.09