|

파이썬 iterable과 iterator 차이: for문은 내부에서 무엇을 호출할까

파이썬 iterable과 iterator 차이: for문은 내부에서 무엇을 호출할까
for문은 iterable에서 iterator를 얻고 next를 반복 호출하는 흐름으로 이해할 수 있습니다.

파이썬 iterable과 iterator 차이는 for문을 많이 쓰는 사람일수록 한 번은 꼭 정리해야 하는 주제입니다.

핵심은 for문이 iterable을 iterator로 바꾼 뒤 next를 반복 호출한다는 점입니다. 이 글은 Python 공식 문서를 기준으로 iter, next, StopIteration, generator의 관계를 단계적으로 설명합니다.

파이썬 iterable iterator 차이 요약 카드
iterable은 반복할 수 있는 대상이고, iterator는 다음 값을 하나씩 꺼내는 객체입니다.

파이썬 iterable과 iterator를 먼저 나누자

iterable은 반복할 수 있는 대상입니다. list, tuple, dict, str, range처럼 for문에 넣을 수 있는 객체가 대표적입니다. iterator는 실제로 값을 하나씩 꺼내는 객체입니다.

numbers = [10, 20, 30]      # iterable
it = iter(numbers)          # iterator

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

list 자체가 값을 하나씩 꺼내는 손은 아닙니다. `iter(list)`를 호출했을 때 만들어지는 iterator가 next 호출에 반응합니다.


for문은 내부에서 무엇을 할까

Python for문은 사람이 보기에는 간단하지만 내부 흐름은 명확합니다. 먼저 `iter()`를 호출해 iterator를 얻고, 그 iterator에 `next()`를 반복 호출합니다.

for item in numbers:
    print(item)

# 개념적으로는 아래 흐름과 비슷하다
iterator = iter(numbers)
while True:
    try:
        item = next(iterator)
    except StopIteration:
        break
    print(item)

그래서 for문에 들어갈 수 있다는 말은 ‘iter()로 iterator를 얻을 수 있다’는 뜻에 가깝습니다.


StopIteration은 에러라기보다 종료 신호

iterator는 더 이상 꺼낼 값이 없을 때 StopIteration을 발생시킵니다. for문은 이 신호를 보고 반복을 정상 종료합니다. 그래서 일반적인 for문에서는 StopIteration을 직접 볼 일이 많지 않습니다.

  • next(iterator)는 다음 값을 반환한다
  • 값이 남아 있지 않으면 StopIteration이 나온다
  • for문은 StopIteration을 잡고 반복문을 끝낸다
  • 직접 next를 호출할 때는 종료 처리를 직접 생각해야 한다

직접 iterator를 만들면 구조가 보인다

클래스로 iterator를 만들려면 보통 `__iter__()`와 `__next__()`를 구현합니다. iterator 자신의 `__iter__()`는 보통 자기 자신을 반환합니다.

class Countdown:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

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

for n in Countdown(3):
    print(n)

이 예제를 보면 iterator가 내부 상태를 가지고 다음 값을 하나씩 계산한다는 점이 드러납니다.


generator는 iterator를 쉽게 만드는 문법

generator 함수는 `yield`를 사용해 iterator를 더 짧게 만들게 해 줍니다. Python 공식 문서도 generator를 iterator를 만드는 간단하고 강력한 도구로 설명합니다.

def countdown(start):
    current = start
    while current > 0:
        yield current
        current -= 1

for n in countdown(3):
    print(n)

직접 클래스로 `__next__()`를 작성하지 않아도, generator는 실행 위치와 지역 상태를 기억하면서 다음 값을 내놓습니다.


실무 체크리스트

  1. for문에 넣을 수 있는지 보려면 iterable인지 확인한다
  2. 한 번 소비한 iterator는 다시 처음으로 돌아가지 않는다는 점을 기억한다
  3. 같은 데이터를 여러 번 반복해야 하면 list 같은 container를 유지한다
  4. 큰 데이터를 한 번씩 흘려보낼 때는 generator를 검토한다
  5. StopIteration은 for문 바깥에서 직접 next를 쓸 때만 신경 써도 된다

정리

iterable를 이해할 때는 용어부터 외우기보다 이 도구가 어떤 경계를 나누려는지 먼저 보는 편이 좋습니다. 오늘 글의 기준은 후보를 좁히는 흐름, 반복 상태의 이동, 입력 검증의 책임, 빌드 입력의 변경 빈도, 읽기와 쓰기의 복잡도 차이를 구분하는 것입니다.

함께 보면 좋은 내부 글은 파이썬 enumerate는 왜 편할까, 파이썬 map과 filter, list comprehension 차이, 파이썬 데코레이터란 무엇인가입니다. 외부 기준은 Python Docs – Glossary: iterable, Python Docs – Glossary: iterator, Python Tutorial – Iterators를 확인했습니다.

함께보면 좋은 글