글을 거의 다쓰고 나서 엄청 잘 설명된 게시글을 발견했다.
요기로
파이썬에서 이터레이터는 여러개의 요소를 가지는 컨테이너(리스트, 튜플, 셋, 사전, 문자열)에서 각 요소를 하나씩 꺼내 처리할 수 있게 해주는 객체
class IterClass(object):
def __init__(self, start, last):
self.current = start
self.max = last
def __iter__(self):
return self
def __next__(self):
if self.current > self.max:
raise StopIteration
else:
self.current += 1
return self.current - 1
요런식으로 구현되어 있다고 생각하면 된다.
for문은 iterable한 컨테이너 객체에 대해서 iter() 메소드를 호출하여 이터레이터 객체를 만들고 next()를 메소드를 호출하여 요소를 차례대로 가져온다.
>>> s = 'abc'
>>> it = iter(s)
>>> it
<str_iterator object at 0x000001B6297FB760>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
File "<pyshell#6>", line 1, in
next(it)
StopIteration
위의 작업을 한 줄에 끝내주는 게 for문인것이다.
반복구문을 돌릴 수 있는 객체를 iterable 하다고 한다.
iterable하다고 iterator는 아니다. list는 iterator가 아니다.
iter함수를 이용하면 iterable한 객체를 iterator로 만들 수 있다.
next함수를 이용해 값을 불러올 수 있다.
iterator를 직접 만들 수도 있는데, iter, next 메서드가 있으면 된다.
즉, 이터레이터는 반복가능한 여러요소가 있는 컨테이너에 대해서 요소를 차례대로 꺼내 처리할 수 있게 해주는 것이며, 우리가 흔히 쓰는 for문은 iterable한 컨테이너를 이터레이터로 만들고 이의 next메소드를 호출하여 차례대로 요소를 반환해주는 것이다.
제너레이터는 이터레이터의 특별한 버전이다.
제너레이터는 return의 역할이 yield
다. yield를 여러번 사용하여 return하면 모든 변수가 사라지는 것과 다르게 yield하고 나서도 내용을 기억하고 있다가 다음 yield문을 만나면 이를 토대로 값을 반환한다.
이러한 특성때문에 대용량데이터를 처리할 때 좋다. 모든 함수가 실행되는 것이 아니라 필요할때마다 리턴되기 때문이다.
피보나치 수열을 구현한다.
>>> class fib:
... def __init__(self):
... self.prev = 0
... self.curr = 1
...
... def __iter__(self):
... return self
...
... def __next__(self):
... value = self.curr
... self.curr += self.prev
... self.prev = value
... return value
...
>>> f = fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> def fib():
... prev, curr = 0, 1
... while True:
... yield curr
... prev, curr = curr, prev + curr
...
>>> f = fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
yield curr 이후의 작업을 기억하고 다음 yield가 호출됐을때 이용한다.