제너레이터는 제너레이터 함수가 호출될 때 반환되는 이터러블 객체이다. 제네레이터 함수는 일반적인 함수와 비슷하게 생겼지만 yield
구문을 사용해 데이터를 원하는 시점에 반환하고 처리를 다시 시작할 수 있다. 일반적인 함수는 진입점이 하나라면 제네레이터는 진입점이 여러개라고 생각할 수 있다. 이러한 특성때문에 제네레이터를 사용하면 원하는 시점에 원하는 데이터를 받을 수 있게된다.
|
|
동작
yield
문이 포함된 함수를 실행하면 제너레이터 객체가 반환되는데 이 때는 함수의 내용이 실행되지 않는다.next()
라는 빌트인 메서드를 통해 제네레이터를 실행시킬 수 있으며 next() 메서드 내부적으로 iterator 를 인자로 받아 이터레이터의__next__()
메서드를 실행시킨다.- 처음
__next__()
를 호출하면 함수의 내용을 실행하다yield
문을 만났을 때 처리를 중단한다. - 이 때 모든 local state는 유지되는데 변수의 상태, 명령어 포인터, 내부 스택, 예외 처리 상태를 포함한다.
- 그 후 제어권을 상위 컨텍스트로 양보(yield)하고 또
__next__()
가 호출되면 제네레이터는 중단된 시점부터 다시 시작한다.
yield
문의 값은 어떤 메서드를 통해 제네레이터가 다시 동작했는지에 따라 다른데,__next__()
를 사용하면 None이고send()
를 사용하면 메서드로 전달 된 값을 갖게되어 외부에서 데이터를 입력받을 수 있게 된다.
장점
List
, Set
, Dict
표현식은 iterable 하기에 for
표현식 등에서 유용하게 쓰일 수 있다. 하지만 해당 객체들은 Collection
특성상 가진 데이터를 메모리에 담고 있어야 하기 때문에 큰 값을 다룰 때는 성능상 불리하다. 제너레이터는 yield
를 통해 필요한 값만 받아 쓰기 때문에 모든 값을 메모리에 들고 있을 필요가 없게 된다.
|
|
리스트가 여러번 사용될 수 있는 반면 b
제네레이터는 한번 사용된 후 소진된다. 이는 모든 이터레이터가 마찬가지인데 List
, Set
등은 이터러블하지만 이터레이터는 아니기에 소진되지 않는다.
|
|
while True
구분으로 제공받을 데이터가 무한하거나, 모든 값을 한번에 계산하기엔 시간이 많이 소요되어 그때 그때 필요한 만큼만 받아 계산하고 싶을 때 제네레이터를 활용할 수 있다.