파이썬에서 자주 접할 수 있는 용어인 이터레이터와 제너레이터에 대해 정리해보았다.
iterable한 객체를 내장 함수 또는 iterable객체의 메소드로 객체를 생성할 수 있다. 그렇다면 iterable한 객체란 무엇일까?
iterable, 반복 가능한 객체이다. 순서대로 다음 값을 리턴할 수 있는 객체를 의미하며, 파이썬에서 대표적으로 iterable한 타입은 list, dict, set, str, bytes, tuple, range 등이 있다.
예를 들어, list 객체는 다음과 같이 반복문을 통해 값을 사용할 수 있다. 이렇게 내부 요소를 하나씩 리턴할 수 있는 요소를 iterable한 객체라고 할 수 있다.
a = [1, 2, 3]
for item in a:
print(item)
iter함수를 통해 iterable 객체를 iterator로 만들 수 있으며, iterator로 변경 후에 __next__()
함수 호출이 가능하다.
# 1. iter() 함수 사용 전
print(a.__next__) # AttributeError 발생
# 2. iter() 함수 사용 후
a = iter(a)
#a = [1, 2, 3].__iter__() # 같은 결과
print(a.__next__()) # 1 출력
print(a.__next__()) # 2 출력
print(a.__next__()) # 3 출력
print(a.__next__()) # StopIteration Exception
__next__()
함수를 호출해서 값을 반복적으로 꺼내 쓸 수 있고, 마지막 값까지 모두 꺼낸 후에는 StopIteration 예외가 발생한다.
iterator를 생성해주는 함수이며, 함수안에 yield
키워드를 사용한다.
yield가 호출되면 암시적으로 return이 호출되며, 한번 더 실행되면 실행되었던 'yield' 다음 코드가 실행된다. 다음의 예제를 확인해보자.
def simple_gen():
yield "Hello"
yield "World"
gen = simple_gen()
print(gen) # Hello 출력
print(next(gen)) # World 출력
print(next(gen)) # StopIteration Exception
처음 gen을 호출할 때에는 simple_gen()함수를 실행하다가 yield 키워드를 만나면서 "Hello" 값을 return하고 해당 위치를 기억한다.
이후, next함수를 통해 다시 함수가 호출되면 앞서 return한 이후부터 코드를 실행하고 yield 키워드를 만나면 또 다시 "World" 값을 return한다.
이렇게 생성한 genertaor는 iterable한 객체가 되며 for문에서 사용할 수 있게된다.
def list_generator():
a = [1, 2, 3]
for i in a:
yield i #한번씩 값을 바깥으로 전달
gen = list_generator()
#case 1.
print(list(gen)) # [1, 2, 3] 출력
#------------------------------
#case 2.
print(next(gen)) # 1 출력
print(next(gen)) # 2 출력
print(next(gen)) # 3 출력
#------------------------------
이와 같이, 제너레이터는 함수를 끝내지 않은 상태에서 yield를 사용해 값을 바깥으로 전달할 수 있다.
return은 반환 즉시 함수가 끝나지만 yield는 잠시 함수 바깥의 코드가 실행되도록 주도권을 양보하여 값을 가져가게 한 뒤 다시 제너레이터 안의 코드를 계속 실행하는 방식이다.
모든 제너레이터는 이터레이터에 포함된다고 할 수 있다.