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을 통해 메모리 사용량을 줄일 수 있다는 장점이 있습니다.