[Python] Iterable과 Iterator

Iterable과 Iterator에 대한 정리


환경

  • Python


Iterable과 Iterator의 정의

Iterable

  • 멤버들을 한번에 하나씩 돌려줄 수 있는 객체
  • 문서에는 An object capable of returning its members one at a time.으로 나와있다.
  • “이터러블의 예로는 모든 (list, str, tuple 같은) 시퀀스 형들, dict 같은 몇몇 비 시퀀스 형들, 파일 객체들, __iter__()나 시퀀스 개념을 구현하는 __getitem__()메서드를 써서 정의한 모든 클래스의 객체들이 있습니다.”
  • 이터러블 객체가 내장 함수 iter() 에 인자로 전달되면, 그 객체의 이터레이터를 돌려줍니다.
>>> a = [1,2,3]
>>> type(a)
<class 'list'>
>>> a_iterator = iter(a)
>>> type(a_iterator)
<class 'list_iterator'>

Iterator

  • 데이터의 스트림을 표현하는 객체
  • 문서에는 An object representing a stream of data.라고 나와있다.
  • 이터레이터의 __next__() 메서드를 통해 반복적으로 호출하면 스트림의 데이터를 차례대로 돌려준다. 더 이상의 데이터가 없으면 StopIteration 예외를 발생시킨다.
  • 이터레이터는 이터레이터 객체 자신을 돌려주는 __iter__() 메서드를 가지기 때문에, 이터레이터는 이터러블이기도 하다.
>>> a = [1,2,3]
>>> type(a)
<class 'list'>
>>> a_iterator = iter(a)
>>> type(a_iterator)
<class 'list_iterator'>
>>> dir(a_iterator)
['__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 Types)

이터레이터 프로토콜

  • 파이썬은 이터레이션 개념을 지원한다. 이것은 아래 두 개의 메서드(iterator.__iter__()iterator.__next__())를 사용해서 구현되며 이것들은 사용자 정의 클래스가 이터레이션을 지원할 수 있도록 하는데 사용된다.
  • 문서에서는 컨테이너에 대한 예제만 나와있는데 글을 읽어보면 임의의 클래스나 객체에 대해서도 구현이 가능해보인다.
  • 이터레이터 객체 자체는 다음과 같은 두 가지 메서드를 지원해야 하는데, 둘이 함께 이터레이터 프로토콜 (iterator protocol) 를 이룬다.

iterator.__iter__()

  • 이터레이터 객체 자신을 돌려준다.

iterator.__next__()

  • 객체의 다음 항목을 돌려준다. 더 항목이 없으면 StopIteration 예외를 일으킨다.


컨테이너에서의 이터레이션

  • 컨테이너 객체가 이터레이션 지원을 제공하려면 아래에 있는 한 가지 메서드를 정의해야한다.
  • 위에 이터레이터 프로토콜에 따라서 바로 구현해도 되는거 같다. (글쓴이의 추측)

container.__iter__()


추가 궁금한 사항

Iterable과 Iterator의 관계

  • 상단에 정리를 해두었지만 반복을 통해 멤버들을 한번에 하나씩 돌려줄 수 있는 객체들을 모두 통틀어서 Iterable이라고 하고 그 Iterable를 구현하는 방법중 하나가 Iterator를 사용한거다.
  • Iterable로 만들고자하는 클래스에 __iter()__ 메서드를 구현해서 Iterator를 반환하도록 만들고 그 Iterator는 상단 이터레이터 형(Iterator Types)에 나온 이터레이터 프로토콜에 따라 자신을 반환하는 __iter()__와 다음 항목을 돌려주는 __next()__를 구현하면 된다.


__iter__()와 __getitem__()의 차이


정리 및 마무리

처음에는 IterableIterator가 뭔지가 궁금했는데 알면 알수록 조금 복잡했었다.

정리하면 Iterable은 멤버들을 한번에 하나씩 돌려줄 수 있는 객체들을 말하며 list, str, dict, 파일 객체 그리고 __iter__()나 시퀀스 개념을 구현하는 __getitem__()를 통해 구현한 객체들이 그 예시이다. 반복을 통해 속한 멤버들을 하나씩 반환할 수 있는 특징을 가진 객체들을 통칭한다고 보면 될거 같다.

이제 Iterator는 데이터의 스트림을 표현하는 객체로 이터레이터 프로토콜에 따라 두 가지 메서드(iterator.__iter__()iterator.__next__())를 구현한 객체이다. Iterator__iter__() 메서드가 구현되어 있기 때문에 Iterable하기도 하다. 이 Iterator를 이용해 Iterable한 객체를 만들 수 있다.

실제 리스트를 보면 __iter__() 메서드를 직접 호출하거나 리스트를 내장 함수 iter()에 넘겨주면 Iterator를 반환하며 이 Iterator 내부에는 두 가지 메서드(iterator.__iter__()iterator.__next__())가 정의되어 있다.

a = [1, 2, 3]

print(type(a))
print(type(a.__iter__()))
print(type(iter(a)))

print()

print(dir(a))
print(dir(a.__iter__()))
print(dir(iter(a)))
<class 'list'>
<class 'list_iterator'>
<class 'list_iterator'>

['__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']
['__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__']
['__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__']


참고자료