Iterator

폐쇄맨·2020년 7월 23일
1

WeCode

목록 보기
7/22

Iterator?

iterator는 반복될 수 있는 객체이다. 모든 값들을 순회할 수 있다는 뜻 이다. 파이썬에서 좀 더 명확히 말하자면, 이터레이터는 __iter__()__next__() 메서드로 구성된 이터레이터 프로토콜을 구현한 객체이다.

Iterable container

리스트, 튜플, 딕셔너리, 세트 모두가 iterable한 객체이다. 이들은 우리가 iterator 객체를 가질 수 있게 해주는 iterable container이다.

iter() 메서드를 사용하여 iterator 객체를 얻을 수 있다.

mytuple = ("apple", "banana", "cherry")
myit = iter(mytuple)

print(next(myit))
print(next(myit))
print(next(myit))

>>> python main.py
apple
banana
cherry

심지어 문자열도 iterable한 객체이기 때문에 iter()를 사용하면 iterator를 얻을 수 있다.

mystr = "banana"
myit = iter(mystr)

print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))

>> python main.py
b
a
n
a
n
a

Looping through an Iterator

for 반복문을 사용해 iterable 객체를 루핑할 수 있다.

mytuple = ("apple", "banana", "cherry")

for x in mytuple:
  print(x)

>> python main.py

for 반복문은 실제로 iterator 객체를 생성한 후 next()를 매회마다 실행한다.

Create an Iterator

이터레이터로서의 클래스를 만들기 위해서 __iter__() 메서드와 __next__() 메서드를 반드시 구현해야한다. 파이썬에서 클래스에 대해 처음 배울 때, 모든 클래스는 객체를 생성할 때 무언가 초기화를 해주는 __init__() 메서드를 포함한다고 공부한다. __iter__() 메서드도 비슷(?)하다. 어떤 동작을 구현하던 마지막에는 반드시 iterator 객체를 반환해야 한다. __next__() 메서드도 마찬가지로 어떤 기능을 구현하던 마지막에는 반드시 시퀀스의 다음 아이템을 반환해야한다.

다음은 1부터 숫자를 하나씩 늘려가며 리턴하는 이터레이터의 예제이다.

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self

  def __next__(self):
    x = self.a
    self.a += 1
    return x

myclass = MyNumbers()
myiter = iter(myclass)

print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))

>> python main.py
1
2
3
4
5

StopIteration

위의 예제는 원한다면 next() 호출을 영원히 계속 할 수 있고 for loop에서 사용되면 무한루프에 빠지게된다. 계속 반복되는 것을 방지하기 위해 StopIteration을 사용한다.

아래는 a가 20보다 크면 StopIteration을 발생시키는 예제이다.

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self

  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration

myclass = MyNumbers()
myiter = iter(myclass)

for x in myiter:
  print(x)

>> python main.py
1
2
... 생략
19
20

Assignment

문제

다음의 간단한 키를 출력하는 딕셔너리에 대한 for 문을 while문으로 구현해 보세요.

D = {'a':1, 'b':2, 'c':3}
for key in D.keys():
    print(key)

정답

StopIteration에 대해 공부하고 났더니 방향이 보였다. 일부러 StopIteration을 발생시켜 while문을 빠져나가는 것으로 생각하여 코드를 작성하였더니 잘 동작하였다.

D = {'a':1, 'b':2, 'c':3}

keys = iter(D.keys())
while True:
    try:
        key = next(keys)
    except StopIteration:
        break
    print(key)
    
>> python assignment.py
a
b
c

소감

iterator를 공부하기 전에는 그냥 for문에 동작하도록 만들어진줄 알았다. 그래서 "좀 잘만들었디 🌈" 이렇게 생각하고 있었는데, 지금은 그 실체를 좀 파악한 것 같다. 바름님께서 데코레이터에 관한 질문에 답변을 해주실 때 "당장은 직접 이런 코드를 구현할 일이 없지만, 나중에 장고같은 프레임워크를 커스터마이징해야 하는 경우가 있는데, 그 때 프레임워크의 코드를 수정하려면 당장 쓰지 않아도 파이썬 문법에 익숙해져 있어야 수월하게 다가갈 수 있다"라고 말씀하셨는데, 지금 그 iterator도 비슷한 맥락으로 받아들이면 될 것 같다.

profile
폐쇄맨

0개의 댓글