제너레이터

YangJiWon·2020년 8월 28일
0

python

목록 보기
8/12

제너레이터

  • iterator 객체의 한 종류
  • 제너레이터를 전달하면서 next 함수를 호출하면 값을 하나씩 얻을 수 있습니다.
  • 제너레이터를 만드는 방법은 두 가지가 있습니다.

1. 제너레이터 함수 : 제너레이터를 만들기 위한 함수 정의

  • 제너레이터 예제
def gen_num():
    print('first number')
    yield 1 # yield가 하나라도 들어가면 제너레이터가 됩니다.
    print('second number')
    yield 2
gen = gen_num()
type(gen) # <class 'generator'>
next(gen) # first number 1
next(gen) # first number 2
  • 마지막까지 실행했음에도 다시 next 함수를 호출하면 이번에는 StopIteration 예외가 발생합니다. 그 이유는 제너레이터 객체 역시 iterator객체이기 때문입니다.
  • 함수 호출 이후에 그 실행의 흐름을 next 함수가 호출될 때까지 미루는 특성을 가리켜 lazy evalutaion이라고 합니다.

제네레이터의 장점

  • 제너레이터를 사용하면 그렇지 않은 경우보다 메모리를 절약할 수 있습니다.
  • 제너레이터를 사용하는 경우 리스트의 길이에 상관없이 메모리 공간의 크기가 동일한데, 그 이유는 제너레이터 객체는 반환할 값들을 미리 만들어서 저장해 두지 않기 때문입니다.

yield from

def get_nums():
    ns = [0, 1, 0, 1, 0, 1]
    for i in ns:
        yield i
g = get_nums()
next(g) # 0
next(g) # 1
  • 여기에서 for 문을 이용하여 yield를 통해 ns의 값을 하나씩 전달하였습니다. 하지만 이것보다 쉽게 코드를 작성하는 방법이 있습니다. 바로 yield from을 사용하는 것입니다.
def get_nums():
    ns = [0, 1, 0, 1, 0, 1]
    yield from ns
g = get_nums()
next(g) # 0
next(g) # 1

2. 제너레이터 표현식 : 제너레이터를 만들기 위한 식

  • 제네레이터 표현식은 문법 구성이 리스트 컴프리헨션과 거의 비슷합니다.
  • 리스트 컴프리헨션으로 만들기
def show_all(s):
    for i in s:
        print(i, end = ' ')

st = [2 * i for i in range(1, 10)]
show_all(st) # 2, 4, 6, ....
  • 제네레이터 표현식으로 만들기
def show_all(s):
    for i in s:
        print(i, end = ' ')


g = (2 * i for i in range(1, 10))
show_all(st) # 2, 4, 6, ....
  • 제너레이터 표현식은 [...]에서 (...)으로 바뀌었을 뿐 그 안을 채우는 방법은 리스트 컴프리헨션과 똑같습니다.

정리

  • 생성되는 값들을 순서대로 하나씩 가져다 쓰면 되는 상황에서는 이렇듯 제너레이터를 기반으로 코드를 작성하는 것이 합리적입니다. (메모리를 절약할 수 있기 때문)
  • map과 filter도 제너레이터 함수이고, iterator 객체이자 제너레이터 객체입니다.
  • 제너레이터 표현식은 제너레이터 함수보다 간결합니다. 하지만 표현해야할 식이 복잡하다면 그 장점을 잃게 될 수도 있습니다. 따라서 상황별로 제너레이터를 만드는 방법을 적절히 이용해야 합니다.
profile
데이터데이터데이터!!

0개의 댓글