C
Python/중급/Lesson 11

제너레이터 (Generator)

1시간·theory
이 챕터
3/8
Python

제너레이터 (Generator)

🎯 이 lesson 을 읽고 나면

이 lesson 을 다 읽고 나면 아래 3가지를 자신 있게 할 수 있습니다.

  • ✅ yield 가 함수를 제너레이터 로 만드는 메커니즘
  • ✅ 메모리 효율 (큰 list 대신 generator)
  • ✅ itertools 활용 (chain, islice, groupby)

학습 목표를 체크리스트로 두고 다 답할 수 있게 되면 lesson 을 닫으세요.

generator 5가지 핵심 — 코드 + 실행 결과

generator = 값을 하나씩 지연 생산하는 함수. 메모리 절약 + 무한 시퀀스 가능.


1. list vs generator — 메모리 차이

python
# list — 1억 개를 메모리에 한 번에
큰_리스트 = [x * x for x in range(100_000_000)]
# 메모리 약 4GB ⚠️ 컴퓨터 멈춤

# generator — 필요할 때마다 1개씩
큰_제너 = (x * x for x in range(100_000_000))
# 메모리 거의 0 — 함수 객체 하나만 ✅

import sys
print(sys.getsizeof(큰_제너))     # 200 byte 정도

[ ] → list, ( ) → generator. 한 글자 차이로 메모리 천억 배 차이.


2. yield — generator 만들기

python
def 카운트(n):
    """1 부터 n 까지 하나씩 돌려준다"""
    for i in range(1, n + 1):
        yield i              # ← 한 개씩 양보

# 호출만으로는 실행 안 됨
gen = 카운트(5)
print(gen)                   # <generator object 카운트 at 0x...>

# for 로 꺼낼 때 비로소 실행
for n in 카운트(5):
    print(n, end=" ")        # 1 2 3 4 5

yield 만나면 값 양보 + 함수 일시 정지. 다음 호출 때 그 줄부터 재개.


3. next() — 한 개씩 꺼내기

python
def 무한_카운트():
    n = 1
    while True:              # 무한 루프 OK!
        yield n
        n += 1

한_개씩 = 무한_카운트()
print(next(한_개씩))         # 1
print(next(한_개씩))         # 2
print(next(한_개씩))         # 3
# 메모리 무한 — 끝없이 가능

⚠️ list 로는 무한 시퀀스 불가능 — generator 만의 강점.


4. 실무 패턴 — 큰 파일 한 줄씩

python
def 큰_로그_읽기(파일경로):
    """1GB 로그 파일도 메모리 절약하며 처리"""
    with open(파일경로) as f:
        for 줄 in f:
            if "ERROR" in 줄:
                yield 줄.strip()

# 사용
for 에러줄 in 큰_로그_읽기("server.log"):
    print(에러줄)
# 메모리: 한 줄씩만 — 1GB 파일도 OK

5. return vs yield 차이

python
# return — 한 번에 다 만들어 반환
def 한번에(n):
    return [i * i for i in range(n)]    # 1억이면 메모리 폭발

# yield — 하나씩
def 하나씩(n):
    for i in range(n):
        yield i * i                      # 1억도 OK

# 결과물은 같음, 메모리 사용은 천지 차이
'''
한번에(5) → [0, 1, 4, 9, 16] (즉시 반환)
하나씩(5) → <generator> → 0, 1, 4, 9, 16 (필요할 때)
'''

한 줄 요약

비교listgenerator
만들기[x for x in xs](x for x in xs)
함수return listyield x (반복)
메모리모두 한 번에1개씩
무한불가능가능
다시 사용OK한 번만 (소진)

핵심: 큰 데이터·무한·스트리밍 → generator. 작은 데이터 → list.

💻 나쁜 예시 — 대용량 데이터를 리스트로 한 번에 메모리 적재
# 1억 개 숫자를 리스트로 — 메모리 수 GB 소비
def get_all_numbers(n):
    result = []
    for i in range(n):
        result.append(i * i)
    return result  # 모든 값이 메모리에 존재

# 호출 시 즉시 수 GB 메모리 사용
numbers = get_all_numbers(100_000_000)
for num in numbers:
    process(num)
💻 좋은 예시 — yield로 지연 평가
from typing import Generator, Iterator
import sys

# 제너레이터 함수 — 값을 하나씩 생성 (메모리 O(1))
def square_numbers(n: int) -> Generator[int, None, None]:
    """n개의 제곱수를 하나씩 생성"""
    for i in range(n):
        yield i * i  # 호출자에게 값 반환 후 여기서 일시정지

# 제너레이터 표현식 — 더 간결
squares = (i * i for i in range(100_000_000))

print(sys.getsizeof(list(range(1000))))    # ~8056 bytes
print(sys.getsizeof(range(1000)))          # 48 bytes (이터레이터)
print(sys.getsizeof(squares))             # 104 bytes (제너레이터)

# yield from — 내부 이터러블 위임
def flatten(nested: list) -> Generator:
    for item in nested:
        if isinstance(item, list):
            yield from flatten(item)  # 재귀 위임
        else:
            yield item

print(list(flatten([1, [2, [3, 4]], 5])))  # [1, 2, 3, 4, 5]

# 실전: 대용량 CSV 파일 처리
def read_large_csv(filepath: str) -> Iterator[dict]:
    """메모리 효율적으로 대용량 CSV 처리"""
    import csv
    with open(filepath, encoding='utf-8') as f:
        reader = csv.DictReader(f)
        for row in reader:
            yield row  # 한 줄씩 처리, 메모리 O(1)

# 데이터 파이프라인 조합
def process_pipeline(filepath: str):
    rows = read_large_csv(filepath)
    filtered = (row for row in rows if int(row['age']) >= 18)  # 필터
    transformed = ({**row, 'name': row['name'].upper()} for row in filtered)  # 변환
    for item in transformed:  # 지연 실행
        save_to_db(item)

🐍 실행해보기 — 제너레이터 (Generator)

위 개념을 실제로 코드로 실행해보세요. 값을 바꿔가며 어떻게 동작하는지 직접 확인하는 게 가장 빠른 학습.
✏️ Python 코드
📟 콘솔 출력
▶ 실행 버튼을 눌러보세요
🐍 Pyodide로 실제 Python 실행 — 첫 실행 시 로딩 3~5초 소요

🤖 AI 에게 이렇게 요청해보세요

이 lesson 의 개념을 알면 AI 에게 구체적으로 지시할 수 있습니다. 막연한 "고쳐줘" 가 아니라 어휘를 가진 요청 — 그게 토큰 절약의 출발점입니다.

  • "이 큰 list 빌드를 generator (yield) 로 바꿔서 메모리 절약해줘"
  • "itertools 사용해서 더 효율적으로 만들어줘"

왜 이게 토큰을 줄이나

개념을 모를 땐 AI 답변을 받고도 "그게 뭐예요?" 를 다시 물어야 합니다. 그 "다시 물음" 이 토큰을 잡아먹습니다. 개념 한 번 익혀두면 대화가 한 번에 끝납니다.

먼저 읽으면 좋은 개념: 람다 함수
다음 추천: 데코레이터
제너레이터 - Python