본문 바로가기
C.W.K.
Stream
Lesson 01 of 07 · published

반복자 규약 — for 문 아래에서 일어나는 일

~22 min · iterator, protocol, iter, next, StopIteration

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

반복 가능한 객체와 반복자는 역할이 다르다

리스트·문자열 같은 반복 가능한 객체에 iter()를 호출하면 반복자를 얻어. 반복자는 next()를 호출할 때마다 값을 하나 내주고, 끝에서는 StopIteration으로 완료를 알려.

for 문을 풀어 보면 규약이 보인다

for는 먼저 iter로 반복자를 만든 뒤 next를 되풀이하고 StopIteration에서 멈춰. 그래서 이 규약만 지키면 파일, 제너레이터, 직접 만든 객체도 같은 문법으로 걸을 수 있어.

반복자는 보통 한 번만 흐른다

리스트는 매번 새 반복자를 만들 수 있지만 반복자 자체는 이미 지나간 값을 되돌리지 않아. 한 번 소비한 파일이나 제너레이터를 다시 걷으면 빈 결과가 나오는 이유야. 여러 번 써야 한다면 원본 반복 가능한 객체에서 새 반복자를 만들거나 의도적으로 값을 저장해.

원칙: 값을 저장한 모음과 값을 흘려보내는 반복자를 구분하면 메모리와 수명 문제를 훨씬 쉽게 읽을 수 있어.

Code

iter와 next를 직접 호출하기·python
items = [10, 20, 30]
it = iter(items)             # items 위의 iterator

print(next(it))              # 10
print(next(it))              # 20
print(next(it))              # 30

try:
    next(it)
except StopIteration:
    print("소진")

# next() 는 디폴트 값으로 예외 피할 수 있어
it = iter([1, 2])
print(next(it, None))        # 1
print(next(it, None))        # 2
print(next(it, None))        # None  — 예외 없음
for 문을 규약 호출로 풀어 보기·python
items = [10, 20, 30]

# 이거
for x in items:
    print(x)

# 이거랑 같음
it = iter(items)
while True:
    try:
        x = next(it)
    except StopIteration:
        break
    print(x)
한 번 소비하면 끝나는 반복자·python
items = [1, 2, 3]
it = iter(items)

list(it)                     # [1, 2, 3]
list(it)                     # []   <- 이미 소진

# 근데 *iterable* 자체는 다시 반복 가능 — 매번 새 iterator
for x in items:
    pass
for x in items:              # 잘 됨 — 매 루프마다 새 iter()
    print(x)
직접 반복자 규약 구현하기·python
class CountDown:
    def __init__(self, start):
        self.n = start

    def __iter__(self):
        return self            # iterator 가 자기 자신 반환

    def __next__(self):
        if self.n <= 0:
            raise StopIteration
        v = self.n
        self.n -= 1
        return v

for x in CountDown(3):
    print(x)
# 3
# 2
# 1

# iterable 소비하는 모든 거랑 작동
print(list(CountDown(5)))    # [5, 4, 3, 2, 1]
print(sum(CountDown(10)))    # 55
반복 가능한 객체와 반복자 구분하기·python
lst = [1, 2, 3]              # iterable, iterator 가 아님
it = iter(lst)               # iterator (list.__iter__ 호출)

# iterator 는 next() 지원
print(next(it))              # 1

# iterable 은 (iter()를 거치기 전에는) next()를 지원하지 않음
try:
    next(lst)
except TypeError as e:
    print(e)                 # 'list' object is not an iterator

# 대부분 iterator 는 iterable *도* — __iter__ 에서 self 반환
print(iter(it) is it)        # True

External links

Exercise

Repeater(value, times)를 구현해 value를 정확히 times번 내준 뒤 StopIteration으로 끝내. for 문과 list(Repeater(...))로 확인하고, 같은 Repeater 인스턴스에 list를 두 번 호출했을 때 두 번째가 빈 리스트가 되는 이유를 설명해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.