이터러블 객체

이터러블 객체는 순서가 있는 자료형으로 문자열, 리스트, 튜플, 딕셔너리, range 객체가 있다. 이터러블 객체들은 for 문 안에서 사용할 수 있다. 과연 이터러블 객체는 for 문안에서 어떻게 동작하는지 살펴보자.

>>> print(dir([10, 20, 30]))
['__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']

>>> print(type([10, 20, 30].__iter__()))
<class 'list_iterator'>

__iter__는 클래스의 이터레이터 객체를 만들어주는 메서드인 것을 볼 수 있다.

>>> iter_obj = [10, 20, 30].__iter__()
>>> print(iter_obj)
<list_iterator object at 0x7fe1a3069160>

>>> print(dir(iter_obj))
['__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__']

여기서 눈여겨 봐야 할 것은 __next__라는 메서드이다. 이터러블 객체안에는 __next__라는 메서드가 포함되어 있다.

>>> print(iter_obj.__next__())
10
>>> print(iter_obj.__next__())
20
>>> print(iter_obj.__next__())
30
>>> print(iter_obj.__next__())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

정리하면 __iter__()를 통해 이터러블 객체를 만들고, __next__()함수를 호출해서 이터 하나씩 출력을 하고 더 이상 출력할 것이 없으면 StopIteration이라는 오류를 내뱉는 것이다.

이터레이터 생성

  • 이터레이터 클래스를 정의해준다.
  • __iter__ 메서드를 정의해준다.
  • __next__ 메서드를 정의해준다.
class Seasons:
    def __init__(self):
        self.season_list = ['spring', 'summer', 'autumn', 'winter']
        self.idx = 0  # 현재 인덱스 
        self.max_num = 4   # 인덱스의 최대 개수

    # __iter__ 메소드 호출시 객체 자기 자신을 리턴
    def __iter__(self):
        return self

    def __next__(self):
        if self.idx < self.max_num:
            curr_idx = self.idx
            self.idx += 1
            return self.season_list[curr_idx]
        else:
            raise StopIteration

이제 Seasons는 우리만의 이터러블 객체로 사용할 수 있다.

>>> for i in Seasons():
...     print(i)
... 
spring
summer
autumn
winter

Seasons는()를 실행하면 자동으로 __iter__를 호출해서 이터러블 객체를 만들고, __next__를 호출해서 하나씩 i에 담게 된다.

>>> iter_obj = Seasons().__iter__()
>>> print(iter_obj.__next__())
spring
>>> print(iter_obj.__next__())
summer
>>> print(iter_obj.__next__())
autumn
>>> print(iter_obj.__next__())
winter
>>> print(iter_obj.__next__())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 15, in __next__
StopIteration