일반적인 함수의 경우 사용이 종료되면 결과값을 호출부로 반환 후 함수 자체를 종료시킨 후 메모리 상에서 클리어 된다. 하지만 generator 함수가 실행 중 yield 를 만날 경우, 해당 함수는 그 상태로 정지 되며, 반환 값을 next() 를 호출한 쪽으로 전달 하게 된다. 이후 해당 함수는 일반적인 경우 처럼 종료되는 것이 아니라 그 상태로 유지되게 된다. 즉, 함수에서 사용된 local 변수나 instruction pointer 등과 같은 함수 내부에서 사용된 데이터들이 메모리에 그대로 유지되는 것이다.
def generator(n):
i = 0
while i < n:
yield i
i += 1
for x in generator(5):
print(x)
0
1
2
3
4
파이썬 3.3 이상 부터 사용가능
def generator():
a = [1, 2, 3]
for i in a:
yield i
gen = generator()
list(gen) # [1, 2, 3]
위와 같이 iterable한 객체를 yield할 때에는 아래와 같이 for문 대신 yield from
으로 값을 전달할 수 있다.
def generator():
a = [1, 2, 3]
yield from a
gen = generator()
list(gen) # [1, 2, 3]
()
를 사용하면 generator object로 생성된다.
>>> [ i for i in xrange(10) if i % 2 ]
[1, 3, 5, 7, 9]
>>> ( i for i in xrange(10) if i % 2 )
<generator object <genexpr> at 0x7f6105d90960>
memory를 효율적으로 사용할 수 있다.
list 는 list 안에 속한 모든 데이터를 메모리에 적재하기 때문에 list의 크기 만큼 차지하는 메모리 사이즈가 늘어나게 된다. 하지만 generator 의 경우 데이터 값을 한꺼번에 메모리에 적재 하는 것이 아니라 next() 메소드를 통해 차례로 값에 접근할 때마다 메모리에 적재하는 방식이다.
import sys
a = [i for i in range(1000)] # <class 'list'>
b = (i for i in range(1000)) # <class 'generator'>
sys.getsizeof(a) # 9016
sys.getsizeof(b) # 112
Lazy evaluation, 계산 결과 값이 필요할 때까지 계산을 늦추는 효과를 볼 수 있다.
이러한 Generator는 데이타가 무제한이어서 모든 데이타를 리턴할 수 없는 경우나, 데이타가 대량이어서 일부씩 처리하는 것이 필요한 경우, 혹은 모든 데이타를 미리 계산하면 속도가 느려서 그때 그때 On Demand로 처리하는 것이 좋은 경우 등에 종종 사용된다.
출처
https://wikidocs.net/16069
https://bluese05.tistory.com/56