본문 바로가기
wecode/TIL 정리

위코드 Pre Course - 파이썬의 Generator

by 왕거 2020. 7. 24.
#send() 사용 예제

def generator_send():
    received_value = 0

    while True:

        received_value = yield
        print("received_value = ",end=""), print(received_value)
        yield received_value * 2

gen = generator_send()
next(gen)
print(gen.send(2))

next(gen)
print(gen.send(3))

################################################################3
# 실행 결과
received_value = 2
4
received_value = 3
6

파이썬에서 사용하는 함수 중 특수한 경우라고 볼 수 있는 Generator 함수에 대해서 정리한다.

 

Generator

  • 제네레이터 라고 읽으면 된다.
  • 일반적인 함수와 제네레이터 함수의 차이
    • 일반 함수는 return을 통해서 작동 결과를 호출 지점으로 반환한다.
    • 제네레이터 함수는 yield를 통해서 작동 결과를 호출 지점으로 "산출"한다
  • "산출한다."의 의미
    • 제네레이터 함수는 반복자 객체를 사용할 수 있으며, __next__를 받기 전에는 작동 이후 지점에 머무르며 대기하고, __next__를 확인하면 다시 함수의 처음로 복귀해서 로직을 수행한다.
  • 제네레이터 함수는 send()를 사용해서 도중에 연산에 사용할 값을 전달할 수 있다.
#send() 사용 예제

def generator_send():
    received_value = 0

    while True:

        received_value = yield
        print("received_value = ",end=""), print(received_value)
        yield received_value * 2

gen = generator_send()
next(gen)				#제네레이터 함수 호출
print(gen.send(2))			#값을 send()로 전달

next(gen)				#제네레이터 함수 호출
print(gen.send(3))			#값을 send()로 전달

################################################################3
# 실행 결과
received_value = 2
4
received_value = 3
6

 

 

제네레이터 표현식 (Generator Expression)

  • Lazy evaluation을 사용하기 위한 방법
    • Lazy evaluation이란 실행을 지연시킨다는 뜻
  • 컴프리헨션 사용과 비슷하지만 그냥 괄호 -() 를 사용해서 표현한다.
    • 컴프리헨션은 대괄호-[] 사용
# generator expression 예제

L = [ 1,2,3]

def generate_square_from_list():
    result = ( x*x for x in L )		#generator expression 사용
    print(result)
    return result

def print_iter(iter):
    for element in iter:
        print(element)

print_iter( generate_square_from_list() )

#################################################################
# 사용 결과
<generator object generate_square_from_list.<locals>.<genexpr> at 0x02C9ABF8>
1
4
9

 

Assignment

# 이 코드를 분석하자
import time

def print_iter(iter):
    for element in iter:
        print(element)

def lazy_return(num):
    print("sleep 1s")
    time.sleep(1)
    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)

Lazy evaluation이란?

  • 정의  :  어떠한 값이 실제로 쓰일 때까지 그 값의 계산을 뒤로 미루는 것
  • 어떤 값이 필요할 때에만 연산을 수행하는 것은 컴퓨팅 자원의 절약에 도움이 된다.
  • 전체 연산의 시간도 줄이는 데 도움이 된다.
  • 단 코드가 점점 복잡해지고 난해해질 수 있기 때문에 남발하는 것은 금물!
# generator expression을 사용하여 Lazy evaluation 확인 예제
def return_one():
    print("return 1")
    return 1

print("[let's make one_generator !]")
one_generator = (return_one() for x in range(4))

print("[let's print one_generator !]")
for one in one_generator:
    print(one)
    
#########################################################
# 실행 결과
[let's make one_generator !]
[let's print one_generator !]
return 1
1
return 1
1
return 1
1
return 1
1

 

 

리스트 컴프리헨션과 Lazy evaluation의 차이점은?

  • 컴프리헨션의 경우는 조건을 대괄호를 사용해서 묶어주지만 Lazy evaluation은 괄호를 사용한다.
# comprehension과 lazy evalution의 비교
test_list = [1, 2, 3]

def print_iter(iter):
    for i in iter:
        print(i)

def num_return(num):
    print("print {}".format(num))
    return num

print("Comprehension List=")
comp_list = [num_return(i) for i in test_list]
print_iter(comp_list)

print("Generator Expression")
generate_exp = (num_return(i) for i in test_list)
print_iter(generate_exp)

#######################################################
# 실행 결과
Comprehension List=
print 1
print 2
print 3
1
2
3
Generator Expression
print 1
1
print 2
2
print 3
3
  • comprehension의 경우
    • num_return을 3회 연속 실행한 후 print_iter을 1회 실행했다.
    • 주어진 조건에 맞게 한꺼번에 처리한 후 다음 로직을 수행함
  • Lazy evalutaion의 경우
    • num_return 1회 실행 후 print_iter을 1회 실행하는 과정을 3회 반복했다.