함수에 yield를 사용하여 이터레이터를 생성하는 함수이다.
참고(https://dojang.io/mod/page/view.php?id=2412)
yield에 대한 이해를 높이기 위해 다음과 같이 코드를 작성하였다
def num_generator():
yield 0 # 0을 외부로 전달
yield 1 # 1을 외부로 전달
yield 2 # 2를 외부로 전달
for i in num_generator:
print(i)
############## 결과값 ##############
0
1
2
yield가 들어간 함수를 자세히 보기위해 아래 코드를 실행해보았다.
>>> g = num_generator()
>>> g
<generator object number_generator at 0x03A190F0>
>>>dir(g)
['__class__', '__del__', '__delattr__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__',
'__gt__', '__hash__', '__init__', '__init_subclass__',
'__iter__', '__le__', '__lt__', '__name__', '__ne__',
'__new__', '__next__', '__qualname__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame',
'gi_running', 'gi_yieldfrom', 'send', 'throw']
우리가 여기서 주목 해야하는것은 __iter__, __next__
라는 요소이다.
제너레이터에서 필수로 하는 요소이고 이것이 어떻게 행동하는지 살펴보자.
g.__next__() # 0
g.__next__() # 1
g.__next__() # 2
g.__next__()
#Traceback (most recent call last):
# File "<pyshell#29>", line 1, in <module>
# g.__next__()
#StopIteration
g.__next__()
가 동작할 때마다 num_generator()에 작성한 값이 하나씩 튀어 나온다. 마지막 동작에선 더 이상의 이터레이터가 없으니 StopIteration이라는 예외를 발생시킨다.
이렇게 동작하는 Lazy evaluation 이라 부른다.
def num_send():
num = 0
while True:
num = yield # 값을 외부로부터 받는다.
print(num) # 받은 값을 출력한다.
return yield num * 2 # 받은 값 * 2를 외부로 전달.
gen = num_send()
next(gen) # 제너레이터를 실행 <-- gen.__next__() 와 같은 동작.
print(gen.send(1)) # 1 (받은 값) , 2 (전달한 값) 이 출력된다.
x = [i for i in range(1,11) if i % 2 == 0] # comprehension
>>> x
[2,4,6,8,10]
y = (i for i in range(1, 11) if i % 2 == 0) # comprehension과 유사하지만 tuple 처럼 소괄호()로 표현하였다.
>>> y
<generator object <genexpr> at 0x024F02A0>
Comprehension은 생성과 동시에 모든 값들이 배열 속에 담겨있지만
제너레이터 표현식의 경우 필요에 의해 값을 생성한다.
import time
L = [1,2,3]
def print_iter(iter):
for element in iter:
print(element)
def lazy_return(num):
print("sleep 1s")
time.sleep(1) # time 모듈
return num
print("comprehension_list=")
comprehension_list = [ lazy_return(i) for i in L ]
print_iter(comprehension_list)
print("generator_exp=")
generator_exp = ( lazy_return(i) for i in L )
print_iter(generator_exp)
####### 결과 #######
comprehension_list=
sleep 1s
sleep 1s
sleep 1s
1
2
3
generator_exp=
sleep 1s
1
sleep 1s
2
sleep 1s
3
Comprehension의 함수 실행순서
print("comprehension_list=")
lazy_return([1,2,3])
print_iter([1,2,3])
제너레이터 표현식의 함수 실행순서
print("generator_exp=")
lazy_return(1)
print_iter(1)
lazy_return(2)
print_iter(2)
lazy_return(3)
print_iter(3)