🖇 iterable과 iterator는 무엇인가?
🖇 iterable에서 __iter__ 를 호출하면 iterator가 나온다
🖇 iterable vs iterator
파이썬을 공부하다 보면 iterable(이터러블)과 iterator(이터레이터) 라는 단어를 자주 접하게 될 것이다.
둘의 차이를 이해하고 넘어가는 것이 중요한데
for, while 같은 반복문이 내부적으로 iterator를 사용해서 동작하며map, filter, zip 등은 모두 iterator를 반환하고처음 들었을 때는 헷갈리기 쉽지만,
한 번 제대로 이해해두면 파이썬의 반복 처리 로직이 눈에 보이기 시작할 것이다.
iterable 반복할 수 있는 객체
iterator 값을 차례대로 꺼낼 수 있는 객체
| 개념 | 설명 | 예시 |
|---|---|---|
| iterable | 반복 가능한 객체 (for문 등에서 사용 가능) | list, tuple, str, set, dict 등 |
| iterator | 값을 하나씩 꺼낼 수 있는 객체 (next로 접근 가능) | __iter()__로 생성한 객체, generator 등 |
이렇게만 봤을 때는 와닿지 않을 수 있다.
아래에서 더 자세히 살펴보자.
iterable요소가 여러 개 들어있고, 요소를 한 번에 하나씩 꺼낼 수 있는 반복 가능한 객체
e.g., 리스트, 튜플, range(), 문자열, 딕셔너리, 세트
💡 반복 가능한 객체인지 확인하는 방법
dir(객체)를 통해
객체에 __iter__ 메서드가 들어있는지 확인
dir([1, 2, 3])
# __iter__ 확인
['__add__', '__class__', ... '__iter__', ... 'reverse', 'sort']
iterator__next__ 메서드를 사용해서 값을 차례대로 꺼낼 수 있는 객체iterator를 조금 더 이해해 보자.
for i in range(100): 에서
사실은 0부터 99까지 연속된 숫자를 만들어내는 것이 아니라,
0부터 99까지 값을 차례대로 꺼낼 수 있는 이터레이터를 하나만 만들어낸다.
이후 반복할 때마다 이터레이터에서 숫자를 하나씩 꺼내서 반복한다.
연속된 숫자를 미리 만들면 숫자가 적을 때는 상관없지만
숫자가 아주 많을 때는 메모리를 많이 사용하게 되므로 성능에도 불리하다.
파이썬에서는 이터레이터만 생성하고 값이 필요한 시점이 되었을 때 값을 만드는 방식을 사용한다.
-> 지연 평가(lazy evaluation): 데이터 생성을 뒤로 미루는 방식
__iter__를 호출하면 iterator가 나온다반복 가능한 객체(iterable)에서 __iter__를 호출하면 이터레이터가 나온다.
코드를 통해 직접 확인해 보자.
[1, 2, 3].__iter__()
<list_iterator object at 0x03616630>
(1, 2, 3).__iter__()
<tuple_iterator object at 0x107f97040>
range(3).__iter__()
<range_iterator object at 0x107f97840>
'Hello, world!'.__iter__()
<str_iterator object at 0x03616770>
{'a': 1, 'b': 2}.__iter__()
<dict_keyiterator object at 0x03870B10>
{1, 2, 3}.__iter__()
<set_iterator object at 0x03878418>
iterator 에서 어떻게 요소를 꺼낼 수 있을까?
반복 가능한 객체의 이터레이터를 변수에 저장한 뒤
__next__ 메서드 호출하면 된다.
it = [1, 2, 3].__iter__()
it.__next__() # 1
it.__next__() # 2
it.__next__() # 3
it.__next__() # StopIteration 예외 발생
객체 내부에서 실제 동작을 이해하기 위해 __iter__()와 __next__() 를 사용했지만,
우리가 직접 사용할 때는 아래의 내장 함수를 사용하는 것이 일반적이다.
iter(): 반복 가능한 객체에서 이터레이터 호출하기
next(): 이터레이터에서 요소 꺼내기
it = iter([1, 2, 3]) # __iter__() 호출과 동일
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
print(next(it)) # StopIteration 예외 발생
이제 위에서 설명한
for문에서 반복 가능한 객체 동작 과정을 다시 살펴보면 이해가 갈 것이다.
for i in range(3):
1. range에서 __iter__로 이터레이터를 얻는다
2. 한 번 반복할 때마다 이터레이터에서 __next__로 숫자를 꺼내서 i에 저장한다
3. 지정된 숫자 3이 되면 StopIteration을 발생시켜서 반복을 끝낸다
정리하면
⇒ 반복 가능한 객체는 __iter__ 메서드로 이터레이터를 얻는다.
⇒ 이터레이터의 __next__ 메서드로 값 가져오기를 반복한다.
지금까지 살펴본 내용을 요약해 보자.
이제 아래의 표를 보면 iterable 과 iterator 어떻게 다른지 확실하게 이해할 수 있을 것이다.
| iterable | iterator | |
|---|---|---|
| 정의 | 반복 가능한 객체 | 값을 하나씩 꺼낼 수 있는 객체 |
| 목적 | 반복을 시작하기 위한 객체 | 반복을 진행하기 위한 객체 |
| 내부 메서드 | __iter__() | __iter__(), __next__() |
iter() 적용 | O - 이터레이터 생성 | O - 자기 자신을 반환함 |
next() 사용 | X | O - 다음 요소 꺼냄 |
| for문 사용 | O | O |
| 예시 | list, str, tuple, range() 등 | iter(list), file 객체, generator 등 |
| 사용 후 재사용 | O - 반복 여러 번 가능 | X - 재사용 불가(소모형) |
| StopIteration 예외 | X | 반복 끝나면 StopIteration 예외 발생 |
iterable 은 반복 가능한 객체이고,
iterator 는 그 객체에서 값을 하나씩 꺼낼 수 있는 도구이다.모든 iterator는 iterable이지만, 모든 iterable이 iterator는 아니다 :)