TIL 43. Iterable vs Iterator

Drageon Lee·2022년 3월 4일
0

TIL_Python

목록 보기
9/11

Today's topic

지난 번 generator에 대해서 posting을 할 때 generator는 iterator라는 말을 한적이 있다. Python 언어를 공부하면서 iterable과 iterator에 대해서 들어본 적이 있을 것이다. 그냥 영어적으로 해석했을 때는 iterable 한게 iterator가 아닐까? 하고 생각할 수 있다.
물론 iterable 한게 iterator 이긴 하지만, 엄밀히 말하면 다르다. 이번 posting을 통해 iterable과 iterator에 대해서 알아보고 차이점을 비교해 볼 것이다.

👉 What is "iterable"?

먼저 'iterable'은 뭘까?

member(요소)들을 한번에 하나씩 돌려줄 수 있는 객체

즉, iterable 객체는 반복이 가능한 객체를 의미한다.
Iterable 객체의 예로는 sequence type인 list, tuple, str type과 dict, file object 그리고 sequence sementic을 구현하는 __iter__()__getitem__() method를 사용하여 정의한 모든 객체를 나타낸다.
아래는 예시 code 이다.

list = [1,2,3,4,5]
print(dir(list))
# result
['__add__', '__class__', '__class_getitem__', '__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']

위의 예시 code를 봤을 시 list 객체에는 __iter__ method와 __getitem__ method가 있는 것을 확인할 수 있다.
iterable 객체라고 할 때는 __iter__ method는 꼭 가지고 있어야 한다.

👉 How to use "iterable"?

그러면 iterable 객체는 어떤 것들이 있는지 알았는데 이러한 iterable 객체들은 어떻게 사용할까?

Iterable 객체는 for loop나 zip(), map() 등에 사용된다. iterable 객체는 그 자체로 사용하는 것이 아니라, 일반적으로 iter() 내장함수를 통해 iterator 변환하여 사용된다.
하지만, 보통은 iterator로 직접 변환하여 사용하지는 않고 for loop을 통해 iterable한 객체를 사용한다.

for loop에 iterable 객체를 사용하면 for loop이 작동하는 동안 자동으로 임시로 임의의 변수를 만들어 iterator를 잡아둔다. 쉽게 말하면, iterator로 변환하는 과정을 for loop이 돌아가는 동안 자동으로 만들어 주기 때문에 iterable 객체를 iter() 함수로 iterator를 따로 변환해 줄 필요가 없다.

👉 What is "iterator"?

그렇다면 iterator는 뭘까?

데이터의 stream을 표현하는 객체이다.

즉, stream을 기억하고 있기 때문에 객체 내의 요소를 차례대로 꺼낼 수 있는 객체이다. dir()함수로 확인 시 iterator에는 __iter__()__next__() method가 내장되어 있다. 그렇기 때문에 next() 함수로 호출 시에 객체 내의 요소들을 하나 하나 흐름대로 반환해 준다.
즉, __iter__method 와 __next__ method를 가져야지 iterator라고 할 수 있다.
예시로 list를 iter() 함수로 호출 하여 iterator로 만들어 보고 dir()함수로 method를 확인해 보겠다.

list = [1,2,3,4,5]
list_iter = iter(list)
print(dir(list_iter))
# result
'__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__',
'__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']

위의 예시를 확인 시 iterator로 변환해 준 list에는 __iter____next__ method를 가지고 있는 것을 확인할 수 있다.

👉 How to use "iterator"?

위에서 언급한 대로 iterator는 iterable을 iter() 함수 호출로 iterator로 변환해 주거나 generator와 같은 iterator를 직접 생성하는 방법이 있다.

그럼 이것을 어떻게 사용할까? iterable 객체 처럼 for문을 사용하는 방법도 있지만 iterable 객체와 다른 점은 iterator는 __next__ method를 가지고 있기에 next() 함수 호출을 통해 값을 하나씩 불러올 수 있다. 하나씩 불러오다가 더이상 불러올 요소가 없으면 StopIteration 예외를 불러 일으킨다.

아래 예시 code를 통해 확인해 보자.

list = [1,2,3,4,5]
list_iter = iter(list)
print(dir(list_iter))
print(next(list_iter))	#1
print(next(list_iter))	#2
print(next(list_iter))	#3
print(next(list_iter))	#4
print(next(list_iter))	#5
print(next(list_iter))	
# result
Traceback (most recent call last):
  File "/Users/yonggeonlee/Desktop/practice/iterator.py", line 52, in <module>
    print(next(list_iter))
StopIteration

next() 함수 호출로 순서의 흐름대로 객체 내의 요소가 나오는 것을 확인 할 수 있고, 더 이상 불러 낼 요소가 없으면 StopIteration을 불러오는 것을 확인 할 수 있다.

📖 출처 :

My opinion

이번 posting에서는 iterable과 iterator에 대해서 정리해 보았다. 지난 번 posting 했던 generator 전에 정리했으면 좀 더 쉽게 generator에 접근할 수 있었을 텐데 하는 아쉬운 생각도 들지만, 반대로 generator를 정리하고 이 posting을 정리하였기에 좀 더 수월했다는 생각도 든다. 역시나 python은 알면 알수록 흥미롭다.

profile
운동하는 개발자

0개의 댓글