제너레이터는 반복문의 반복을 통제하기 위해 사용하는 루틴/함수이다. 모든 제너레이터는 이터레이터 이기도 하다. 제너레이터에는 매개변수가 존재하고 호출될수 있으며, 연속적인 값을 생성하므로 배열을 리턴하는 함수와도 유사한 면이 있다. 하지만 일반적인 배열을 생성할 때는 모든 값을 포함하고 한번에 리턴하는 반면, 제너레이터는 값을 한번에 하나씩 생성(yield)한다. 그러므로 메모리를 적게 사용할 뿐만아니라 호출자가 초반 몇개의 값을 즉시 처리할 수 있게 한다. 즉, 제너레이터는 함수처럼 생겼지만 이터레이터처럼 행동한다. 출처
def square_numbers(nums):
for i in nums:
yield i * i
my_nums = square_numbers([1, 2, 3, 4, 5]) #1
print my_nums
>> <generator object square_numbers at 0x1007c8f50>
제너레이터가 값을 yield할 때는 메모리에 저장하지 않기 때문에 함수를 실행해도 값이 출력되지는 않는다. 따라서 값을 출력하기 위해서는 next()함수를 통해 하나씩 호출하거나 반복문으로 출력해야 한다. 제너레이터는 특이하게도 yield시 상태를 저장하기 때문에(일반적인 함수는 리턴하면 함수는 끝난다) 값을 생성하고도 종료하지 않고 다음 값을 출력해줄 수 있다. 다만 next()함수를 사용할 경우 값의 개수 이상으로 사용하면 StopIteration예외가 발생한다.
리스트에 List Comprehension이 있는 것처럼 제너레이터에도 같은 기능이 존재한다.
my_nums = (x*x for x in [1, 2, 3, 4, 5])
print my_nums
for num in my_nums:
print num
>>
<generator object <genexpr> at 0x1007c8f50>
1
4
9
16
25
위와 같이 제너레이터를 생성할 수 있다. list comprehension과의 차이는 제너레이터는 값을 요청받았을 때만 불러온다는 것과, 한번만 반복한다는 것 등이 있다. 또한 예에서는 크기가 작았지만, 만약 대용량의 데이터를 리스트로 만들 경우 모든 값을 저장하기 때문에 제너레이터에 비해 훨씬 긴 시간이 걸린다.