본문 바로가기
Python

Python의 Iterable과 Iterator

by 개발자54 2025. 3. 13.

우리가 자주 사용하는 리스트(list), 딕셔너리(dict), 집합(set) 같은 객체들은 모두 반복 가능한 객체이다. 이들 객체는 for문이나 map 함수와 함께 사용할 수 있다.

그렇다면 반복 가능한 객체란 도대체 무엇일까? 그리고 이 반복 가능한 객체는 어떻게 동작하는 걸까?

 


Iterable(반복 가능한 객체)란?

Python 공식 문서에서는 Iterable을 다음과 같이 정의하고 있다.

An iterable is an object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an __iter__() or __getitem__() method.

 

길지만, 핵심만 두 가지 짚어보자면 다음과 같다.

 

  • an object capable of returning its members one at a time : 한 번에 하나씩 요소를 반환
  • objects of any classes you define with an __iter__() or __getitem__() method : __iter__() 또는 __getitem__() 메서드를 가진 객체

잘 와닿지 않는다. 코딩을 하면서 이런 걸 본 기억이 없는 것 같다.

이해가 쉽도록 러프하게 말하면, for문을 통해 반복할 수 있는 객체라고 일단은 생각하면 된다. list, dict, set가 그 예시이다.

 

Iterable의 예시 코드를 한 번 보자.

class Ebook:
    def __init__(self, pages_lst):
        self.pages = pages_lst

    def __iter__(self):
        return EbookReader(self.pages_lst)

 

역시 이해가 가질 않는다.

list, dict, set이 Iterable의 예시라면서?

list, dict, set과는 공통점을 찾아볼래야 찾아볼 수가 없는 듣도보도 못한 클래스가 있다.

이 이상한 모양새의 클래스는 도대체 뭐란 말인가?

 

Python의 기본 자료형인 list, dict, set 등은 C언어(CPython)로 구현되어 있다.

CPython 소스코드를 보면, 이 자료형들도 __iter__ 메서드를 가지고 있어 내부적으로 이터레이터처럼 동작한다. 하지만 우리가 이를 직접 구현할 필요가 없는 이유는 Python이 이미 이런 기능을 제공하기 때문이다. 즉, Python 개발자들이 미리 만들어두었기 때문에, 우리는 list, dict, set이 내부적으로 어떻게 작동하는지 몰라도 자연스럽게 사용할 수 있는 것이다.

 

정리하면, list, dict, set은 우리가 직접 class로 구현하지 않더라도 이미 Python에서 제공하는 내장 타입(Built-in Type)이다.

내부적으로 __iter__()를 구현하고 있어서 for 문에서 사용할 수 있는 Iterable이다.

 

Ebook 클래스를 예제로 보여준 이유는, list와 set이 내부적으로 어떻게 동작하는지를 이해하기 쉽게 만들기 위해서이다.

 

일단은 머릿 속에 Iterable은 __iter__를 가지고 있는 객체이다! 라고만 생각해두자.

 

코드로 다시 넘어가보자.

class Ebook:
    def __init__(self, pages_lst):
        self.pages = pages_lst  # 전자책의 페이지 저장

    def __iter__(self):
        return EbookReader(self.pages_lst)  # 새로운 이터레이터 생성

 

우리 주변의 사물을 예시로 들면 전자책(e-book)이 현실 세계에서의 Iterable이라고 할 수 있겠다.

하지만 Iterable은 존재 자체로는 아무것도 할 수가 없다. 우리가 example_lst = [1, 2, 3] 이라는 코드 자체를 입력하는 것만으로는 아무것도 동작하지 않듯이 말이다.

전자책(Iterable)을 읽으려면, 우리는 전자책 리더기에 전자책을 다운받아야 한다. 여기서 전자책을 다운받아서 여는 행위는, Ebook 객체의 __iter__() 를 호출하는 행위와 같다.

Iterable에서 __iter__()를 호출하면, Iterator라는 것이 반환된다.

 

즉, 우리는 비로소 전자책을 한 장 한 장 넘겨 읽을 수 있는 준비가 된 것이다.

 

그렇다면 Iterator는 무엇일까?


Iterator란?

역시 Python 공식 문서의 정의를 살펴보자.

An iterator is an object that represents a stream of data. It implements the __next__() method and returns the next item in the sequence when called. When no more data is available, StopIteration is raised.

  • an object that represents a stream of data : 데이터의 흐름을 나타내는 객체
  • implements the __next__() method and returns the next item : __next__() 메서드를 구현하며 다음 항목을 반환
  • no more data is available, StopIteration is raised : 반환할 항목이 없을 경우 StopIteration을 반환

복잡해 보이지만,

Iterable 객체의 다음 원소로 이동하는 방법을 알고 있는 객체라고 생각하면 쉽다.

즉 example_lst = [1, 2, 3]의 원소 하나 하나를 읽기 위한 준비 자세를 하고 있는 객체이다.

 

위에서 이야기했던 전자책 이야기를 다시 가져와보자.

전자책 리더기에서 전자책을 열어, 전자책을 한 장 한 장 넘겨 읽을 수 있는 준비가 되었다. 그렇다면 전자책을 넘기기 위해서는 어떻게 해야할까? 다음 페이지로 넘기는 버튼을 눌러야 할 것이다.

그 버튼 역할을 해주는 것이 바로 Iterator__next__()이다.

코드를 통해 살펴보자.

class EbookReader:
    def __init__(self, pages_lst):
        self.pages_lst = pages_lst
        self.index = 0  # 현재 페이지 위치 저장

    def __iter__(self):
        return self  # 이터레이터는 __iter__() 호출 시 자기 자신을 반환

    def __next__(self):
        if self.index >= len(self.pages_lst):
            raise StopIteration  # 마지막 페이지 도달 시 종료
        page = self.pages_lst[self.index]
        self.index += 1
        return page

 

Iterator는 다음 두 가지 조건을 만족해야 한다.

  1. __iter__() 메서드를 가지고 있어야 한다.
  2. __next__() 메서드를 가지고 있어야 한다.

여기까지는 좋다. Iterator가 페이지를 넘기는 역할을 해야하니까 __next__()가 필요한 것은 납득이 가는데, 왜 Iterable의 __iter__()를 통해서 Iterator를 반환했는데, 왜 그 반환한 Iterator에도 또 __iter__()가 있는 것인가 하는 의문이 든다.

 

그것은 iter()는 "이터레이터를 반환해야 한다"는 공식 규칙이 있기 때문이다. 여기서 왜라고 묻고 싶겠지만 공식 문서에서 iter() 함수의 규칙을 그렇게 정해놓았다.

 

그렇다면 위 코드의 Iterator를 실제로 실행시켜보고, 어떤 결과가 나오는지 살펴보자.

pages_lst = ["page_1", "page_2", "page_3"]  # Iterable (반복 가능한 객체)
e_book = EbookReader(pages_lst)
e_book_iterator = e_book.__iter__()  # __iter__()를 호출해 이터레이터 객체를 생성

print(next(e_book_iterator))  # next()를 통해 이터레이터에서 값을 꺼냄. 결과 : page_1
print(next(e_book_iterator))  # page 2
print(next(e_book_iterator))  # page 3
print(next(e_book_iterator))  # StopIteration 예외 발생

 

 

참고로 e_book.__iter__()보다는 iter(e_book)을 사용하는 것이 좋지만, 이해를 돕기 위해 클래스 내에 정의된 메서드 형태를 그대로 사용하였다. iter() 함수는 객체가 이터레이터인지 자동으로 확인하고, 필요하면 이터레이터를 만들어 주는 함수이다.


Iterable, Iterator의 차이

둘의 차이점을 간단히 요약하면 다음과 같다.

  • Iterable: __iter__() 메서드를 가지고 있으며, 이 메서드는 Iterator를 반환
  • Iterator: __iter__()와 __next__() 메서드를 가지고 있으며, 반복을 수행

'Python' 카테고리의 다른 글

+= 연산자의 비밀  (1) 2025.03.16
Pycharm 유용한 단축키 정리 (수시 업데이트)  (0) 2022.12.06

댓글