2What — 이터레이터와 제너레이터란?
3- 이터레이터(Iterator): __iter__()와 __next__() 두 메서드를 구현한 객체로, 데이터를 한 번에 하나씩 꺼내는 프로토콜
4- 제너레이터(Generator): yield 키워드로 이터레이터를 간결하게 만드는 함수
5- 핵심 원리는 지연 평가(lazy evaluation) — 값을 미리 계산해 메모리에 올리지 않고, 요청받을 때마다 하나씩 생산한다
6Why — 왜 지연 평가가 현대 Python의 핵심인가
7- 메모리 폭발 방지: 수십 GB 로그 파일을 리스트로 읽으면 RAM이 터진다. 이터레이터로 한 줄씩 처리하면 메모리 사용량이 상수(O(1))로 유지된다
8- 무한 수열 표현: 피보나치 수열, 센서 스트림처럼 끝이 없는 데이터를 리스트에 담는 것은 불가능하다. 제너레이터는 무한 시퀀스를 자연스럽게 표현한다 (Beazley, 2009)
9- 딥러닝 데이터 로더: PyTorch의 DataLoader는 수백만 장 이미지를 배치 단위로 yield하는 이터레이터 — 전체 데이터셋을 메모리에 올리지 않고 학습한다 (Paszke et al., 2019)
10- 파이프라인 합성: UNIX 파이프처럼 이터레이터를 체이닝하면 데이터가 단계별로 흘러간다 — 중간 리스트 없이 변환·필터·집계를 한 패스로 처리
11핵심 사실 — for 루프의 비밀
12- Python의 for 루프는 내부적으로 이터레이터 프로토콜을 사용한다:
13 - 1) 객체에 iter()를 호출해 이터레이터를 얻고
14 - 2) next()를 반복 호출하며
15 - 3) StopIteration 예외가 발생하면 루프를 종료한다
16- 즉, for x in obj는 사실상 이터레이터 프로토콜의 문법적 설탕(syntactic sugar)이다
17Why — range(10억)이 정수 하나만큼의 메모리를 쓰는 이유
18- range(1000000000)은 10억 개의 정수를 메모리에 만들지 않는다
19- 내부적으로 (start, stop, step) 세 값만 저장하고, 요청 시 산술 계산으로 값을 생성한다
20- Python 2의 range()는 리스트를 반환해 메모리를 낭비했고, Python 3에서 지연 평가 객체로 재설계되었다 (Van Rossum, 2006)
21- 한 문장 정리: range는 숫자를 저장하지 않고 계산하는 레시피를 저장한다
22설계 철학 — '모든 것은 객체'에서 이터레이터 프로토콜로
23- Python은 "모든 것은 객체" 철학을 따른다 — 정수, 함수, 모듈까지 전부 객체
24- 이 철학의 자연스러운 확장: 반복 가능성도 객체의 프로토콜로 정의한다
25- __iter__와 __next__라는 매직 메서드만 구현하면 어떤 객체든 for 루프에 넣을 수 있다
26- 이것이 바로 이터레이터 프로토콜 — 상속이 아닌 프로토콜 기반 설계(덕 타이핑)의 대표적 사례
27- 리스트, 딕셔너리, 파일, range, zip, enumerate 모두 이 프로토콜을 따른다
28비유 — 책 전체 복사 vs 한 페이지씩 넘기기
29- 리스트 = 도서관에서 책 전체를 복사해 가져오기 (메모리에 전부 적재)
30- 이터레이터 = 도서관에 앉아서 한 페이지씩 넘기며 읽기 (필요한 순간에만 접근)
31- 100만 페이지짜리 백과사전이라면? 복사는 불가능하지만, 한 페이지씩 읽기는 언제든 가능하다
32실전 사례 요약
33- 로그 파싱: 50GB 서버 로그를 open()으로 줄 단위 이터레이션 → 메모리 수 KB로 처리
34- 무한 스트림: IoT 센서 데이터를 제너레이터로 실시간 소비
35- ML 파이프라인: tf.data.Dataset, PyTorch DataLoader 모두 이터레이터 패턴 기반 (Abadi et al., 2016)
36- 대용량 CSV: pandas read\_csv(chunksize=1000)도 내부적으로 이터레이터 반환