TIL | Python | Generator

이도운·2021년 12월 30일
0

TIL

목록 보기
13/73
post-thumbnail

Generator

제너레이터는 Iterator 객체의 한 종류이다. 때문에 제너레이터를 통해서 next 함수를 호출하면 값을 하나씩 얻을 수 있다.

제너레이터를 마드는 방법에는 두가지가 있다. 제너레이터 함수와 제너레이터 표현식이 그것이다.

아래는 함수를 기반으로 만든 제너레이터 예시다.

def generator_num():
   print("first")
   yield 1
   print("second")
   yield 2
   print("third")
   yield 3
# 제너레이터 함수 정의
# yield가 하날라도 들어가면 제너레이터가 된다

g = generator_num() # 제너레이터 객체 생성 

next(g) # next 함수 호출

마지막 yield가 실행되고 다시 next 함수를 호출하면 StopIteration 예외가 발생한다. 제너레이터 객체 역시 Iterator 객체이기 때문이다. 참고로 함수 호출 이후에 그 실행의 흐름을 next 함수가 호출 될 때까지 미루는 특성을 가리켜 lazy evaluation 이라 한다.

이제 제너레이터의 장점에 대해서 한번 알아보겠다. 아래는 그 예시다.

def gen_pows(s):
   for i in s:
      yield i ** 2

st = gen_pows([1,2,3,4,5])

for i in st:
   print(i, end=" ")

위 예시는 제너레이터를 기반으로 작성되었다. 위 예시를 제너레이터 기반이 아닌 형태로 작성할 수도 있을 것이다. 하지만 그렇게 된다면 인자로 주어지는 리스트 크기에 따라서 메모리 공간을 차지하게 될 것이다. 하지만 제너레이터는 리스트의 길이에 상관없이 사용하는 메모리 공간의 크리가 같다. 이유는 제너레이터 객체는 반환할 값들을 미리 만들어서 저장하지 않기 때문이다.

이제 제너레이터 객체를 생성하는 방법 중 다른 하나인 제너레이터 표현식에 대해서 알아보겠다.

제너레이터 표현식은 리스트 컴프리헨션과 비슷하다. 리스트 컴프리헨션은 [ ... ] 을 사용하지만 제너레이터 표현식은 ( ... ) 을 사용한다.

제너레이터와 리스트 컴프리헨션

CODE

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)
    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

위 결과는 무엇을 의미하는가? 리스트 컴프리헨션은 리스트 원소들을 미리 결과를 보고 저장하는 반면에 제너레이터의 경우 원소들을 호출 될 때 생성하는 것을 의미한다.

이것이 제너레이터가 갖는 lazy evaluation 특성이라고 할 수 있다.

참고

1. 윤성우 열혈 파이썬 중급편

profile
⌨️ 백엔드개발자 (컴퓨터공학과 졸업)

0개의 댓글