한양과학기술고등학교

에듀테크 프로젝트 대시보드

제너레이터 (yield)

yield lazy generator expression yield from

yield 가 있는 함수는 호출해도 실행되지 않고, 값을 필요할 때 하나씩 만들어 냅니다.

1. 기본

def count_up(n):
    i = 0
    while i < n:
        yield i          # 여기서 멈췄다가 다음 요청 때 이어감
        i += 1

gen = count_up(3)        # 아직 아무것도 실행 안 됨
next(gen)                # => 0
next(gen)                # => 1
for x in count_up(3):    # => 0, 1, 2
    print(x)

2. 왜 쓰는가 — 메모리

# 리스트: 1천만 개를 전부 메모리에
squares = [x * x for x in range(10_000_000)]

# 제너레이터: 한 번에 하나씩, 메모리 O(1)
squares = (x * x for x in range(10_000_000))
total = sum(squares)

# 무한 스트림도 가능
def naturals():
    n = 1
    while True:
        yield n
        n += 1

3. 파일·스트림 처리

def read_large(path):
    with open(path, encoding="utf-8") as f:
        for line in f:            # 파일 객체 자체가 제너레이터
            yield line.rstrip()

def only_errors(lines):
    for line in lines:
        if "ERROR" in line:
            yield line

# 파이프라인 — 한 줄씩 흘러감
for err in only_errors(read_large("app.log")):
    print(err)

4. yield from

def chain(*iterables):
    for it in iterables:
        yield from it        # for x in it: yield x 의 축약

list(chain([1, 2], [3, 4]))   # => [1, 2, 3, 4]

def flatten(nested):
    for item in nested:
        if isinstance(item, list):
            yield from flatten(item)
        else:
            yield item

5. 제너레이터 표현식

sum(len(line) for line in file)          # 인자로 넘길 때 괄호 생략
any(x.is_valid() for x in items)
max((score(x) for x in candidates), default=0)

sorted((x for x in data if x > 0))

6. 특징과 주의

제너레이터는 일회용
  • 한 번 소진하면 다시 순회 불가 — 재사용하려면 다시 생성하거나 list() 로 저장
  • len() 불가, 인덱싱 불가 (itertools.islice 사용)
  • 예외/종료 시 with 블록이 제대로 닫히도록 try/finally 또는 contextlib
"명시적인 것이 암시적인 것보다 낫다 (Explicit is better than implicit)"