[Python] 이터레이터 iterator
이터레이터란?
이터레이터(iterator)
는 값을 차례대로 꺼낼 수 있는 객체(obejct)
이다.
만약 연속된 숫자를 미리 만들면 숫자가 적을 떄는 상관없지만 숫자가 아주 많을 때 메모리를 많이 사용하게 되므로 성능에 불리하게 된다.
그래서 파이썬에서는 이터레이터만 생성하고 값이 필요한 시점이 되었을 때 값을 만드는 방식을 사용한다. 즉, 데이터 생성을 뒤로 미루는 것인데 이러한 방식을 지연 평가(lazy evaluation)
이라 한다.
반복 가능한 객체 알아보기
반복 가능한 개체인지 확인을 위해 dir
을 사용하여 __iter__
메서드가 들어있는지 확인해본다.
print(dir([1, 2, 3]))
print([1, 2, 3].__iter__)
it = [1, 2, 3].__iter__()
print(it.__next__())
print(it.__next__())
print(it.__next__())
# print(it.__next__()) # StopIteration Exception
dir
로 확인해보면__iter__
메서드가 들어있다. 리스트에서__iter__
를 호출해보면 이터레이터가 나온다.- 리스트의 이터레이털르 변수에 저장한 뒤
__next__
메서드를 호출해보면 요소를 차례대로 꺼낼 수 있다. - 리스트의 범위를 벗어나게 되면
StopIteration
예외가 발생한다.
리스트 뿐만 아니라 문자열, 딕셔너리, 세트도 __iter__
를 호출하면 이터레이터 객체가 나온다. 그리고 이터레이터에서 __next__
를 호출하면 차례대로 값을 꺼낸다.
클래스에 __iter__
와 __next__
메서드를 모두 구현하면 이터레이터를 만들 수 있다. 특히 __iter__
, __next__
를 가진 객체를 이터레이터 프로토콜(iterator protocol)
을 지원한다고 말한다.
정리하면 반복 가능한 객체는 요솔르 한 번에 하나씩 가져올 수 있는 객체이고, 이터레이터는 __next__
메서드를 사용해서 차례대로 값을 꺼낼 수 있는 객체이다.
시퀀스 객체와 반복 가능한 객체의 차이
리스트, 튜플, range, 문자열은 반복 간으한 객체이면서 시퀀스 객체이다. 하지만, 딕셔너리와 세트는 반복 가능한 객체이지만 시퀀스 객체는 아니다.
시퀀스 객체는 요소의 순서가 정해져 있고, 연속적(sequence)으로 이어져 있어야 하는데, 딕셔너리와 세트는 요소(키)의 순서가 정해져 있지 않기 떄문이다.
따라서 시퀀스 객체가 반복 가능한 객체보다 좁은 개념이다.
즉, 요소의 순서가 정해져 있고 연속적으로 이어져 있으면 시퀀스 객체, 요소의 순서와는 상관없이 요소를 한 번에 하나씩 꺼낼 수 있으면 반복 가능한 객체이다.
이터레이터 만들기
class Counter:
def __init__(self, stop):
self.current = 0 # 현재 숫자
self.stop = stop # 반복을 끝낼 숫자
def __iter__(self):
return self # 현재 인스턴스를 반환
def __next__(self):
if self.current < self.stop:
r = self.current
self.current += 1
return r
else:
raise StopIteration
for i in Counter(3):
print(i, end=" ")
class CountDown:
def __init__(self, start):
self.start = start
def __iter__(self):
return self
def __next__(self):
if self.start > 0:
num = self.start
self.start -= 1
return num
else:
raise StopIteration
for i in CountDown(5):
print(i, end=" ")
-
__iter__
메서드ㅏ를 만드는데 여기서는self
만 반환하면 된다. -
__next__
dㅔ서는 조건에 따라 숫자를 만들어내거나StopIteration
예외를 발생시킨다.
이터레이터는 언패킹(unpacking)이 간으한데 이터레이터가 반복하는 횟수와 변수의 개수가 같아야 한다.
__getitem__
: 인덱스로 접근할 수 있는 이터레이터 만들기
## __getitem__ 메서드 사용
class CountDown:
def __init__(self, stop):
self.stop = stop
def __getitem__(self, index):
if index < self.stop:
return self.stop - index
else:
raise IndexError
print(CountDown(3)[0], CountDown(3)[1], CountDown(3)[2])
for i in CountDown(3):
print(i, end=" ")
__getitem__
메서드를 구현하면 인덱스로 접근할 수 있는 이터레이터가 만들어진다.- 클래스에서
__getitem__
만 구현해도 이터레이터가 되며__iter__
,__next__
는 생략해도 된다.
iter
, next
함수 활용하기
iter
iter
는 반복을 끝낼 값을 지정하면 특정 값이 나올 때 반복을 끝낸다.
반복을 끝낼 값을 sentinel
이라고 부르는데 감시병이라는 뜻이다. 즉, 반복을 감시하다가 특정 값이 나오면 반복을 끝내는 것이다.
import random
it = iter(lambda: random.randint(0, 5), 2) # 2가 나오면 끝난다
print(next(it))
print(next(it))
print(next(it))
print(next(it))
import random
for i in iter(lambda: random.randint(0, 5), 2):
print(i, end=" ")
next
next
는 기본값을 지정할 수 있다. 기본값을 지정하면 반복이 끝나더라도 StopIteration
이 발생하지 않고 기본값을 출력한다.
즉, 반복할 수 있을 때는 해당 값을 출력하고 반복이 끝나면 기본값을 출력한다.
it = iter(range(3))
print(next(it, 10))
print(next(it, 10))
print(next(it, 10))
print(next(it, 10)) # 반복이 끝나면 기본값 출력
예제 1 - 배수 이터레이터 만들기
class MultipleIterator:
def __init__(self, stop, multiple):
self.stop = stop
self.multiple = multiple
self.current = 1
def __iter__(self):
return self
def __next__(self):
r = self.current * self.multiple
if r < self.stop:
self.current += 1
return r
else:
raise StopIteration
for i in MultipleIterator(20, 3):
print(i, end=" ")
print()
for i in MultipleIterator(30, 5):
print(i, end=" ")
예제 2 - 시간 이터레이터 만들기
class TimeIterator:
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __getitem__(self, index):
if index < self.stop - self.start:
time = self.start + index
hour = time // 3600 % 24
minute = time // 60 % 60
second = time % 60
return f"{hour:02}:{minute:02}:{second:02}"
else:
raise IndexError
start, stop, index = map(int, input().split())
for i in TimeIterator(start, stop):
print(i)
print("\n", TimeIterator(start, stop)[index], sep="")
참고 자료
- 파이썬 코딩 도장
Author And Source
이 문제에 관하여([Python] 이터레이터 iterator), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@t1won/Python-이터레이터-iterator저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)