이터러블은 이터레이터를 만들 수 있는 객체이고, 이터레이터는 `next`로 다음 값을 내는 상태 객체다. 끝에서는 StopIteration을 발생시킨다.

def read_moves(lines):
    for line in lines:
        text = line.strip()
        if text:
            yield text

moves = read_moves(open("moves.txt", encoding="utf-8"))

실제 코드에서는 파일을 with 블록 안에서 소비해 파일 수명이 제너레이터보다 짧아지지 않게 한다. 제너레이터도 한 번 소모하면 되돌릴 수 없다.

`yield from other`는 다른 이터러블의 값을 그대로 위임한다. 제너레이터의 `return value`는 StopIteration의 값이 되지만 일반 for문에서는 보이지 않는다.

무한 스트림도 만들 수 있다. 사용하는 쪽에서 `itertools.islice`나 명시적 종료 조건으로 범위를 제한한다. 지연 계산은 오류도 소비 시점까지 늦춘다는 점을 기억한다.

Python 16. 이터레이터와 제너레이터의 핵심 흐름도
그림. 제너레이터는 현재 상태만 유지하며 값을 지연 생산한다.