본문 바로가기

Programming Language/Python

Python generator

* Python generator란?

iterator를 생성해주는 function이다. iterator는 next() method를 이용해 데이터에 순차적으로 접근이 가능한 object이다.

generator는 일반적인 함수와 비슷하게 보이지만, 가장 큰 차이점은 yield 구문이다.

 

* Iterable과 iterator의 이미

- iterable: member를 하나씩 차례로 반환 가능한 object를 의미한다

- sequence type인 list, str, tuple이 대표적이다

- non-sequence type인 dict나 file도 iterable하다고 할 수 있다.

- __iter__()나 __getitem__() 메소드로 정의된 class는 모두 Iterable 하다고 할 수 있다.

- iterable은 for loop 말고도 zip(), map()과 같이 sequence 한 특징을 필요로 하는 작업에 유용하게 사용된다.


zip([iterable, ...])

  This function returns a list of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables.


map(function, iterable, ...)

  Apply function to every item of iterable and return a list of the results.


- Iterator: next() method로 데이터를 순차적으로 호출 가능한 object이다. 만약 next()로 다음 데이터를 불러올 수 없을 경우 StopIteration exception을 발생시킨다.

- Iterable이라고 해서 반드시 Iterator는 아니다.

- iterable을 iterator로 변환하고 싶다면 iter()라는 built-in function을 사용하면 된다.

 

 

* generator 사용 예시

def generator(n):
	i = 0
    while i < n:
    	yield i
        i += 1
for x in generator(5)
	print(x)

결과:

0

1

2

3

4


for문에서 generator 함수가 호출되는데, while문 안에 yield를 만났다고 해서 while문과 generator가 종료되는 것이 아니라 그대로 유지한 상태이다.

for문이 순차적으로 돌면서 generator를 여러번 호출하는데, generator 함수는 처음부터 다시 실행되는 것이 아니라 yield 이후 i+=1 구문을 이어서 실행하게 된다.

 

* generator expression

generator를 좀 더 쉽게 사용할 수 있도록 generator expression을 제공한다.

list와 비슷하지만 [] 대신 ()를 사용하면 된다.

 

* generator를 사용하는 이유

- memory의 효율적인 사용이 가능하다.

list는 list 안에 속한 모든 데이터를 메모리에 적재하기 때문에 List 크기 만큼 차지하는 메모리 사이즈가 늘어나게 된다.

하지만 generator의 경우 데이터 값을 한꺼번에 메모리에 적재하는 것이 아니라 next() method를 통해 차례로 접근할 때마다 메모리에 적재하는 방식이다.

 

- Lazy evaluation, 계산 결과 값이 필요할 때까지 계산을 늦추는 효과가 있다.

 

def sleep_func(x):
	print("sleep...")
    time.sleep(1)
    return x
 
# list example
list = [sleep_func(x) for x in range(5)]

for i in list:
	print(i)
    
  
# generator example  
gen = (sleep_func(x) for x in range(5))

for i in gen:
	print(i)

 

 

list의 경우 list comprehension을 수행할 때, list의 모든 값을 먼저 수행하기 때문에 sleep_func() 함수를 range() 안의 값만큼 한번에 수행하게 된다. sleep_func()에서 수행하는 시간이 길거나 list 값이 매우 큰 경우 처음 수행할 때 그만큼 부담이 된다.

 

하지만 Generator의 경우 generator를 생성할 대는 실제 값을 한번에 로딩하는 것이 아니고, for문이 수행될 때 sleep_func()을 한 번씩 수행하며 값을 불러오게 된다.

수행이 긴 연산을 필요한 순간까지 늦출 수 있다는 점이 특징이다.

 

 

출처: https://bluese05.tistory.com/56, https://bluese05.tistory.com/55