파이썬 이터레이터

Yeonu·2020년 11월 26일
0

Python 이론

목록 보기
24/30
post-thumbnail

👉 이터레이터(iterator)

값을 차례대로 꺼낼 수 있는 객체(object)로 반복자 라고도 한다.

지연 평가(lazy evaluation) : 이터레이터만 생성하고 값이 필요한 시점이 되었을 때 값을 만들어 데이터 생성을 뒤로 미루는 방식
연속된 숫자를 미리 만들면 숫자가 많을 때 메모리를 많이 사용하게 되므로 성능에 불리하다.


👉 반복 가능한 객체 알아보기

dir(객체)를 사용해 객체 안에 __inter__ 메서드가 들어있는지 확인한다.

>>> dir([1, 2, 3])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
'__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__',
'__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__',
'__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend',
'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

리스트의 이터레이터를 변수에 저장한 뒤 __next__ 메서드를 호출해보면 요소를 차례대로 꺼낼 수 있다. 이터레이터는 __next__로 요소를 계속 꺼내다가 꺼낼 요소가 없으면 StopIteration 예외를 발생시켜서 반복을 끝낸다.

>>> it = [1, 2, 3].__iter__()
>>> it.__next__()
1
>>> it.__next__()
2
>>> it.__next__()
3
>>> it.__next__()
Traceback (most recent call last):
  File "<pyshell#48>", line 1, in <module>
    it.__next__()
StopIteration



👉 for와 반복 가능한 객체

먼저 range에서 __iter__로 이터레이터를 얻는다. 한 번 반복할 때마다 이터레이터에서 next로 숫자를 꺼내서 i에 저장하고, 지정된 숫자 3이 되면 StopIteration을 발생시켜서 반복을 끝낸다.



👉 반복 가능한 객체와 시퀀스 객체


반복 가능한 객체 : 요소를 한 번에 하나씩 가져올 수 있는 객체이다.
시퀀스 객체 : 요소의 순서가 정해져 있고 연속적(sequence)으로 이어져 있다.

딕셔너리와 세트는 요소(키)의 순서가 정해져 있지 않아 시퀀스 객체가 아니다.



👉 이터레이터 만들기

range(횟수)처럼 동작하는 이터레이터다.

class Counter:
   def __init__(self, stop):
       self.current = 0    # 현재 숫자 유지, 0부터 지정된 숫자 직전까지 반복
       self.stop = stop    # 반복을 끝낼 숫자

   def __iter__(self):
       return self         # 현재 인스턴스를 반환

   def __next__(self):
       if self.current < self.stop:  # 현재 숫자가 반복을 끝낼 숫자보다 작을 때
           r = self.current          # 반환할 숫자를 변수에 저장
           self.current += 1         # 현재 숫자를 1 증가시킴
           return r                  # 숫자를 반환
       else:                    # 현재 숫자가 반복을 끝낼 숫자보다 크거나 같을 때
           raise StopIteration      # 예외 발생


for i in Counter(3):
   print(i, end=' ')

# 실행 결과
0 1 2



👉 이터레이터 언패킹

다음과 같이 Counter()의 결과를 변수 여러 개에 할당할 수 있다.
이터레이터가 반복하는 횟수와 변수의 개수는 같아야 한다.

>>> a, b, c = Counter(3)
>>> print(a, b, c)
0 1 2
>>> a, b, c, d, e = Counter(5)
>>> print(a, b, c, d, e)
0 1 2 3 4

map도 이터레이터다. 그래서 a, b, c = map(int, input().split())처럼 언패킹으로 변수 여러 개에 값을 할당할 수 있다.



👉 인덱스로 접근할 수 있는 이터레이터 만들기

__getitem__ 메서드를 구현하여 인덱스로 접근할 수 있게 한다.

class Counter:
    def __init__(self, stop):
        self.stop = stop

    def __getitem__(self, index):
        if index < self.stop:
            return index
        else:
            raise IndexError

print(Counter(3)[0], Counter(3)[1], Counter(3)[2])

for i in Counter(3):
    print(i, end=' ')


# 실행 결과
0 1 2
0 1 2

클래스에서 __getitem__만 구현해도 이터레이터가 되며 __iter__, __next__는 생략해도 된다(초깃값이 없다면 __init__도 생략 가능).



👉 iter, next 함수

iter() : 반복 가능한 객체에서 이터레이터를 반환한다.
next() : 이터레이터에서 값을 차례대로 꺼낸다.



👉 iter

반복을 끝낼 값을 지정하면 특정 값이 나올 때 반복을 끝낸다. 이 때 반복 가능한 객체 대신 호출 가능한 객체(callable)를 넣어준다.
반복을 끝낼 값은 sentinel(감시병)이라고 부른다.
iter(호출가능한객체, 반복을끝낼값)

>>> import random
>>> it = iter(lambda : random.randint(0, 5), 2) 
# 0부터 5까지 무작위로 숫자를 생성하다 2가 나오면 반복을 끝냄
>>> next(it)
0
>>> next(it)
3
>>> next(it)
1
>>> next(it)
Traceback (most recent call last):
  File "<pyshell#37>", line 1, in <module>
    next(it)
StopIteration

호출 가능한 객체를 넣어야 하므로 매개변수가 없는 함수 또는 람다 표현식으로 만들어준다.



👉 next

기본값을 지정할 수 있다. 기본값을 지정하면 반복이 끝나더라도 StopIteration이 발생하지 않고 기본값을 출력한다.
next(반복가능한객체, 기본값)

>>> it = iter(range(3))
>>> next(it, 10)
0
>>> next(it, 10)
1
>>> next(it, 10)
2
>>> next(it, 10)
10
>>> next(it, 10)
10




출처, 강의
💡 39.1 ~
💡 39.4

0개의 댓글