이터레이터, 제너레이터

기린이·2022년 5월 20일
0

CS 지식

목록 보기
4/15

글을 거의 다쓰고 나서 엄청 잘 설명된 게시글을 발견했다.
요기로

iterator

파이썬에서 이터레이터는 여러개의 요소를 가지는 컨테이너(리스트, 튜플, 셋, 사전, 문자열)에서 각 요소를 하나씩 꺼내 처리할 수 있게 해주는 객체

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메소드를 호출하여 차례대로 요소를 반환해주는 것이다.

generator

제너레이터는 이터레이터의 특별한 버전이다.
제너레이터는 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가 호출됐을때 이용한다.

참고1, 참고2

profile
중요한 것은 속력이 아니라 방향성

0개의 댓글