return은 함수의 값을 반환하면서 함수를 종료시킵니다.
반면 yield는 함수의 값을 산출하고 종료하지 않습니다.
Generator는 yield를 통해 Iterator를 생성해주는 함수입니다.
메모리 사용성 측면에서 장점을 지니는 Generator 대해 알아보겠습니다.
Iterator는 연속적인 값을 차례대로 꺼낼 수 있는 객체입니다.
연속된 숫자가 아주 많은 경우 많은 메모리를 사용하기 때문에 Iterator를 사용하는 것이 성능적으로 우수할 수 있습니다.
Iterator는 __iter__() 함수를 통해 값을 꺼낼 수 있습니다.
Iterator는 __next__() 함수를 통해 원하는 시점에서 다음 값을 산출할 수 있습니다.
Generator는 Iterator를 생성해주는 함수라고 이해하면 되겠습니다.
Iterator와 마찬가지로 값을 반환한 지점에서 그 다음 값을 다시 호출 할 수 있습니다.
다른 점은 __iter__() 함수와 __next__() 함수가 모두 들어있어 따로 __next__()를 호출하지 않아도 바로 사용할 수 있다는 것입니다.
제너레이터 표현식은 Lazy evaluation을 위해서 사용될 수 있습니다.
Lazy evaluation은 말 그대로 실행을 지연시킨다는 의미입니다.
앞서 말했듯 Iterator, Generator는 __next__() 함수를 통해 다음 값을 산출한다고 이해했습니다.
즉, __next__() 함수를 만나기 전까지 어떠한 실행을 미리 행하지 않고 일부러 지연하는 것을 의미합니다.
제너레이터 표현식의 문법은 리스트 컴프리헨션 문법과 비슷하지만 대괄호( [ ])가 아닌 괄호를 ( ) 사용하여 만드는데요.
Lazy evaluation와 제너레이터 표현식에 대해 코드를 통해 알아보겠습니다.
import time # time 모듈을 불러옵니다.
# 함수의 인자로 받아오는 iter 매개변수의 각각의 요소를 출력합니다.
def print_iter(iter):
for element in iter:
print(element)
# lazy evaluation을 평가하는 함수입니다.
def lazy_return(num):
print("sleep 1s")
time.sleep(1) # parameter 값만큼 함수 실행을 일시정지합니다.
return num
우선 list comprehension의 출력 결과는 다음과 같습니다:
print("comprehension_list=")
comprehension_list = [ lazy_return(i) for i in L ]
print_iter(comprehension_list)
지정한 시간 이후에 데이터 값이 한번에 반환됩니다.
comprehension_list=
sleep 1s
sleep 1s
sleep 1s
1
2
3
반면 generator expressoin는 다음과 같습니다:
print("generator_exp=")
generator_exp = ( lazy_return(i) for i in L )
print_iter(generator_exp)
1초씩 하나의 데이터를 반환하고 있습니다.
generator_exp=
sleep 1s
1
sleep 1s
2
sleep 1s
3
List comprehension의 경우 List를 한번에 만들어두고 함수가 종료되면 값을 한번에 반환합니다.
하지만generator expression을 통해 데이터를 생성하면, 미리 만들어두는 것이 아니라 한번에 하나씩 튜플 데이터를 만들고 그 값을 산출합니다.
미리 만들어 두는 List의 크기가 크면 그만큼 메모리 사용량이 많아질 것입니다.
generator expression을 통해 메모리 사용량을 줄일 수 있다는 장점이 있습니다.