파이썬 반복자(Iterator) 만드는 방법: 완벽 가이드
파이썬에서 반복자는 정말 어디에나 있습니다. 기본 문법만 배우더라도 "반복자(iterator)" 또는 "반복 가능한 객체(iterable)"라는 단어를 접하지 않는 날이 없을 정도입니다.
반복자는 순회(iteration)할 수 있는 객체를 의미합니다. 파이썬에는 반복 가능한 내장 객체들이 여러 가지 있지만, 필요하다면 직접 나만의 반복자를 정의할 수도 있습니다.
이 가이드에서는 파이썬 반복자가 무엇인지, 어떻게 동작하는지, 그리고 코드에서 어떻게 활용할 수 있는지 알아보겠습니다. 또한 직접 반복자를 만들어 보면서 핵심 특징을 실습을 통해 익혀볼 것입니다. 이 가이드의 코드는 Python 3.x 환경에서 동작합니다.
그럼 시작해 보겠습니다!
반복자란 무엇인가?
반복자는 순회할 수 있는 객체로, 해당 객체가 담고 있는 데이터를 한 번에 하나씩 반환합니다.
어떤 객체가 반복 가능한지 확인하는 가장 간단한 방법은 for 루프에 넣어 실행해 보는 것입니다. 객체를 루프로 돌릴 수 있다면 그것은 반복 가능한 객체입니다. 문자열, 리스트, 튜플, 딕셔너리 등이 대표적인 반복 가능한 내장 데이터 타입입니다.
파이썬에서 반복자 객체는 반드시 다음 두 가지 메서드를 가져야 합니다:
__iter__(): 반복자 자체를 반환합니다.__next__(): 반복자에서 다음 값을 가져옵니다.
메서드 이름 앞뒤의 __(언더스코어 두 개)는 특수 함수임을 나타내는 표기입니다. 반복자를 정의하려면 이 두 특수 메서드를 반드시 사용해야 하며, 이 둘을 합쳐서 "반복자 프로토콜(iterator protocol)"이라고 부릅니다. 보통 "iter와 next 메서드"라고 읽습니다.
무한 반복자 만들기
먼저 기본부터 시작해 보겠습니다. 바로 무한 반복자를 만드는 것입니다. 이것이 가장 단순한 형태의 반복자인데, 너무 단순해서 영원히 멈추지 않고 계속 동작한다는 특징이 있습니다. 걱정하지 마세요. 이 문제는 튜토리얼 후반부에서 해결할 예정입니다.
Cakes라는 클래스를 정의하는 것부터 시작해 보겠습니다. 이 클래스가 바로 우리의 반복자 클래스입니다:
class Cakes: def __init__(self, value): self.value = value
__init__ 메서드는 클래스의 객체가 생성되는 즉시 실행됩니다. 이 메서드는 흔히 생성자(constructor)라고 불립니다. 이 예제에서 __init__ 메서드는 value라는 하나의 값을 전달받습니다.
다음으로 반복자 프로토콜을 구현해 보겠습니다:
def __iter__(self): return self def __next__(self): return self.value
__iter__ 메서드는 반복자 객체 자신을 반환하는 역할을 합니다. __next__ 메서드는 지정된 반복 가능한 객체에서 다음 값을 가져오는 역할을 합니다.
여기까지 코드가 제대로 작동하는지 확인해 보겠습니다. 클래스의 객체를 다음과 같이 정의합니다:
cake = Cakes(["Vanilla Sponge"])
지금까지는 잘 되고 있습니다! "왜 아무 일도 일어나지 않지?"라고 생각하실 수도 있는데, 그 이유는 우리 클래스가 단지 반복자 함수만 반환하기 때문입니다.
반복자가 제대로 작동하는지 확인하려면 실제로 순회를 해봐야 합니다. for-in 루프를 사용해 보겠습니다:
for c in cake: print(c)
실행 결과:
Vanilla Sponge Vanilla Sponge …
"바닐라 스펀지의 저주"네요! 콘솔에 계속 같은 값이 출력됩니다. 무슨 일이 일어난 걸까요? 방금 우리는 첫 번째 반복자를 성공적으로 만든 것입니다. 매우 단순하지만, 분명히 작동하고 있습니다.
for-in 루프로 반복자 테스트하기
반복자를 더 유용하게 만들기 전에, for-in 루프의 개념을 잠시 짚고 넘어가겠습니다. 앞선 예제에서 코드를 테스트하기 위해 다음과 같은 for-in 루프를 작성했습니다:
for c in cake: print(c)
for-in 루프는 먼저 __iter__() 메서드를 호출하여 객체의 반복자를 생성합니다. 그다음 __next__()를 더 이상 값이 반환되지 않을 때까지 계속 호출합니다.
for-in 루프를 간단한 while 루프라고 생각하면 이해하기 쉽습니다. 반복자가 반환할 값이 남아 있는 동안, for-in 루프는 그 값들을 계속 꺼내 처리하는 것입니다.
유용한 반복자 만들기
앞서 만든 반복자는 그다지 유용하지 않습니다. 같은 값만 계속 출력할 뿐이니까요. 그래도 엄연히 반복자이긴 합니다. 반복 가능한 객체의 모든 요소를 읽을 수 있는 능력이 있으니까요.
이번에는 파이썬 리스트를 순회하는 반복자를 만들어 보겠습니다. 이 리스트에는 여러 종류의 케이크가 들어 있습니다.
반복자가 무한히 반복되는 것을 막으려면, 반복 가능한 객체 안에 값이 몇 개 있는지, 그리고 반복자가 몇 번 실행되었는지를 추적해야 합니다. 이렇게 하면 리스트의 모든 항목을 순회한 후 반복자의 실행을 멈출 수 있습니다.
새 파이썬 파일을 열고 다음 코드를 붙여넣어 보세요:
class Cakes: def __init__(self, value): self.value = value self.max = len(value) self.count = 0 def __iter__(self): return self def __next__(self): if self.count < self.max: to_return = self.value[self.count] self.count += 1 return to_return else: raise StopIteration
이 반복자는 이전 것보다 조금 더 복잡합니다. 그래서 우리는 먼저 무한 반복자부터 만들었던 것입니다. 이 반복자에서는 세 가지 값을 초기화했습니다:
- value: 순회하고자 하는 항목(리스트)
- max: 반복 가능한 객체에 들어 있는 항목의 개수
- count: 반복자가 실행된 횟수
__next__() 메서드에는 if문이 추가되었습니다. 이 조건문은 반복자가 실행된 횟수(count)가 순회해야 할 항목 수(max)보다 작은지 검사합니다.
count가 max보다 작으면, 반복자는 반복 가능한 객체에서 다음 값을 찾습니다. 그런 다음 count 변수에 1을 더해 남은 항목 수를 추적하고, 마지막으로 계산된 값을 반환합니다.
주목할 점은 count 변수를 증가시키기 전에 to_return 변수에 값을 먼저 할당한다는 것입니다. 이렇게 하면 현재 반복 시점의 값에 올바르게 접근할 수 있습니다.
리스트의 모든 항목을 순회했다면 StopIteration이라는 예외가 발생합니다. 이 예외는 리스트의 모든 항목을 다 순회한 후 프로그램의 반복을 중단시키는 역할을 합니다.
반복자가 잘 작동하는지 확인해 보겠습니다. 메인 프로그램에 다음 코드를 추가하고 실행하세요:
cake = Cakes(["Vanilla Sponge"]) for c in cake: print(c)
실행 결과:
Vanilla Sponge
이번에는 리스트에 항목을 몇 개 더 추가해 보겠습니다:
cake = Cakes(["Vanilla Sponge", "Carrot", "Coffee"]) for c in cake: print(c)
실행 결과:
Vanilla Sponge Carrot Coffee
성공입니다! 케이크 목록을 순회하는 반복자를 완성했습니다. 여기까지 따라오신 여러분, 케이크 한 조각—아니면 적어도 컵케이크 하나—의 자격이 충분합니다.
마치며
반복자를 활용하면 순회 가능한 객체를 직접 만들 수 있습니다. 반복자는 리스트, 문자열 또는 다른 반복 가능한 객체를 순회하며 특정 작업을 수행할 수 있습니다.
도전 과제 하나 어떠신가요? 숫자 리스트를 순회하면서 각 숫자에 2를 곱해 반환하는 반복자를 만들어 보세요.
코드 구조는 위 예제와 비슷할 것입니다. 역시 반복자 프로토콜을 사용하겠지만, 리스트의 각 숫자에 2를 곱한 후 메인 프로그램에 반환하도록 만들면 됩니다.
이제 여러분도 전문가처럼 파이썬에서 나만의 반복자를 작성할 준비가 되었습니다!