한양과학기술고등학교

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

이터레이터 프로토콜

__iter__ __next__ StopIteration iterable

for 문이 내부에서 어떻게 도는지 — iterable 과 iterator 의 구분.

1. iterable vs iterator

정의
  • iterable: __iter__() 가 있어 iter() 로 이터레이터를 내놓는 객체 (list, str, dict…)
  • iterator: __next__() 가 있어 다음 값을 내놓고, 소진되면 StopIteration
  • 이터레이터는 보통 자기 자신도 __iter__ 로 반환 → for 에 직접 사용 가능
nums = [1, 2, 3]         # iterable
it = iter(nums)          # iterator
next(it)                 # => 1
next(it)                 # => 2
next(it); next(it)       # => 3, 그다음 StopIteration

2. for 문의 실제 동작

# for x in obj: body   는 아래와 같다
it = iter(obj)
while True:
    try:
        x = next(it)
    except StopIteration:
        break
    body(x)

3. 클래스로 이터레이터 만들기

class Range2:
    def __init__(self, stop):
        self.stop = stop
        self.i = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self.i >= self.stop:
            raise StopIteration
        self.i += 1
        return self.i - 1

list(Range2(3))          # => [0, 1, 2]

4. 제너레이터가 더 쉬움

class NumberRange:
    def __init__(self, start, stop):
        self.start, self.stop = start, stop
    def __iter__(self):                  # 제너레이터 반환 — __next__ 불필요
        n = self.start
        while n < self.stop:
            yield n
            n += 1

# 매번 새 이터레이터 → 여러 번 순회 가능
r = NumberRange(0, 3)
list(r); list(r)          # 둘 다 [0, 1, 2]

5. itertools 로 이터레이터 다루기

import itertools as it
first5 = it.islice(gen, 5)              # 앞 5개
pairs = it.pairwise([1, 2, 3])         # (1,2),(2,3)  (3.10+)
groups = it.groupby(sorted(data, key=key), key=key)
acc = it.accumulate([1, 2, 3, 4])      # 1, 3, 6, 10

# 이터레이터는 한 번 쓰면 끝 — tee 로 복제
a, b = it.tee(iter([1, 2, 3]))

6. iter() 의 2-인자 형태

# sentinel 값이 나올 때까지 callable 을 반복 호출
with open("data.bin", "rb") as f:
    for chunk in iter(lambda: f.read(4096), b""):
        process(chunk)

# 입력에서 "stop" 나올 때까지
for line in iter(input, "stop"):
    print(line)
"가독성은 중요하다 (Readability counts)"