5.1 Iterable과 Iterator
너희도 알다시피, 이터레이터는 이터레이터 프로토콜을 구현하는 객체로 컬렉션에서 요소를 차례로 가져올 수 있게 해주는 애야. Python에서는 리스트, 튜플, 문자열 같은 시퀀스 요소를 순회할 때 이터레이터가 많이 사용돼.
이제, 이터레이터가 어떻게 구성되어 있고 어떻게 사용하는지 살펴보자.
이터러블 객체 (Iterable)
객체를 for 루프를 통해 순회하려면, 그 객체는 이터러블이어야 해 – Iterable. 이 말은, 우리의 객체가 메소드 __iter__()를 구현하고 있어야 한다는 뜻이고, 이 메소드는 이터레이터 객체를 반환해야 해.
이터레이터 객체 (Iterator)
이터레이터 객체는 특별한 객체로 다음 요소를 반환하는 함수 __next__()를 가지고 있어. 요소가 더 이상 없을 때, 메소드 __next__()는 예외 StopIteration을 호출하여 이터레이션을 중지해.
이터레이터는 또한 메소드 __iter__()를 구현해야 하고, 이 메소드는 자기 자신을 반환해야 해.
Python 내장 함수 사용 예제
이 예제에서 numbers 리스트는 이터러블 객체야. 우리는 iter() 함수를 사용하여 이터레이터를 얻고, next() 함수를 사용하여 StopIteration 예외가 발생할 때까지 요소를 순회할 수 있어.
# 이터러블 객체
numbers = [1, 2, 3, 4, 5]
# 이터러블 객체에서 이터레이터 얻기
iterator = iter(numbers)
# 이터레이터를 사용하여 요소 순회
try:
while True:
number = next(iterator)
print(number)
except StopIteration:
pass
바로 이게, 당신이 이런 코드를 쓸 때 일어나는 일이야:
# 이터러블 객체
numbers = [1, 2, 3, 4, 5]
for number in numbers:
print(number)
5.2 이터레이터의 본질
이터레이터는 우리가 그룹의 요소들을 차례로 순회할 수 있도록 도와주는 어떤 객체야. 구현 방법은 매우 다양할 수 있지. 이제 이터레이터에 요구되는 모든 요건을 충족하는 클래스를 하나 만들어보자.
1단계. 시작으로 클래스를 만들어보자
이것은 start부터 end까지 숫자를 차례로 반환할 거야.
class MyIterator:
def __init__(self, start, end):
self.current = start
self.end = end
2단계. __iter__ 함수 지원
이제 __iter__ 함수를 추가할 필요가 있어. 이 함수는 __next__() 함수를 호출할 수 있는 이터레이터 객체를 반환하게 할거야. 자기 자신의 객체를 반환해도 돼. 이건 금지된게 아니야.
class MyIterator:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
3단계. __next__ 함수 지원
이제, 우리의 이터레이터 객체에 __next__ 함수를 추가해야 해, 이 함수는 리스트의 다음 요소를 반환할 거야. 우리는 그냥 current 변수를 사용할 거야:
def __next__(self):
current = self.current
self.current += 1
return current
4단계. 이터레이터 정지
이터레이터가 이미 계획된 모든 값을 반환한 경우, StopIteration 예외를 던져야 해. 이제 마지막 함수를 조금 수정해보자:
def __next__(self):
if self.current >= self.end: raise StopIteration
current = self.current
self.current += 1
return current
좋아. 이제 우리 이터레이터를 사용할 수 있어. 여기가 전체 코드의 예야:
class MyIterator:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.current >= self.end:
raise StopIteration
current = self.current
self.current += 1
return current
# 사용자 이터레이터 인스턴스 생성
my_iter = MyIterator(1, 5)
# 이터레이터를 사용하여 요소 순회
for num in my_iter:
print(num)
5.3 올바른 이터레이터
이전 예제의 이터레이터가 어때서? 맞아, 이터레이터고 작동해, 하지만 너무 단순해. 동일한 요소 컬렉션을 동시에 여러 이터레이터로 순회할 수 없어.
더 나은 방법은 __iter__ 메소드에서 자기 자신이 아닌 별도의 객체를 반환하여 모든 요소를 올바르게 반환하는 것이야.
예제:
class MyIterable:
def __init__(self, data):
self.data = data
def __iter__(self):
return MyIterator(self.data)
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
item = self.data[self.index]
self.index += 1
return item
# 사용 예제
my_iterable = MyIterable([1, 2, 3, 4])
for item in my_iterable:
print(item)
이 예제에서는 두 개의 클래스가 있어 — 첫 번째는 우리가 이터레이터로 순회할 컬렉션을 전달하는 클래스이고, 두 번째는 이터레이터 자체로, next() 메소드에서 컬렉션의 요소를 반환해. 이건 꽤 간단하지만, 바로 이렇게 이터레이터를 클래스에 추가해야 해.
GO TO FULL VERSION