Python: generator (제너레이터)

dev-swd·2020년 10월 25일
0

python

목록 보기
16/23
post-thumbnail

제너레이터 (발생자)

  • 이터레이터를 생성해주는 함수이다.
  • 이터레이터는 클래스 __iter__, __next__, __getitem__ 를 구현해야 하지만, 제너레이터 함수는 안에서 yield 라는 키워드만 사용하면 끝이다.

iterator 와 차이점

  • iterator 는 __next__ 메서드 안에서 직접 return 으로 값을 반환하지만, generator 는 yield 에 지정한 값이 __next__ 메서드의 반환값으로 나온다.
  • iterator 는 raise 로 StopIteration 예외를 직접 발생시켰지만, generator 는 함수의 끝까지 도달하면 StopIteration 예외가 자동으로 발생한다.
  • generator 는 generator 객체에서 __next__ 메서드를 호출할 때마다 함수 안의 yield 까지 코드를 실행하며 yield 에서 값을 발생시킨다.

yield

함수 안에서 yield 를 사용하면 함수는 제너레이터가 되고, yield 에는 값(변수)를 지정한다.

  • yield 값
  • yield 를 사용하면 값을 함수 바깥으로 전달하면서 코드 실행을 함수 바깥에 양보한다. 따라서 yield 는 현재 함수를 잠시 중단하고, 함수 바깥의 코드가 실행되도록 만든다.

generator & return

제너레이터는 함수를 끝내지 않은 상태에서 yield 를 사용하여 값을 바깥으로 전달한다. return 은 반환 즉시 함수가 끝나지만, yield 는 잠시 함수 바깥의 코드가 실행되도록 양보하여 값을 가져가게 한 뒤 다시 제너레이터 안의 코드를 계속 실행하는 방식이다.

제너레이터는 함수 끝까지 도달하면 StopIteration 예외가 발생하는데,
return 을 사용해서 함수 중간에 빠져나오면 StopIteration 예외가 발생한다.


yield from

  • yield from 반복가능한객체
  • yield from 이터레이터
  • yield from 제너레이터객체

제너레이터 표현식(generator expression)

제너레이터 표현식은 Lazy evaluation 을 위해서 사용될 수 있다.

  • Lazy evaluation - 실행을 지연시킨다는 의미
  • () 를 사용해서 생성한다.

코드 분석

리스트 생성, 출력 (no generator)

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)

# 실행 결과
sleep 1s
sleep 1s
sleep 1s
1
2
3
  1. 리스트 표현식이 사용되어 1, 2, 3 이라는 요소가 각 1초씩 딜레이가 되어 comprehension_list 라는 변수에 값이 적재된다.
  2. 새로운 리스트를 생성하는 처리가 다 끝난 후, 리스트를 한 번에 출력한다.

리스트 생성, 출력 (with generator)

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("generator_exp=")
generator_exp = ( lazy_return(i) for i in L )
print_iter(generator_exp)


# 실행 결과
sleep 1s
1
sleep 1s
2
sleep 1s
3
  1. 제너레이터 표현식으로 생성된 1 이라는 요소를 만들고 출력한다.
  2. 제너레이터 표현식으로 생성된 2 라는 요소를 만들고 출력한다.
  3. 제너레이터 표현식으로 생성된 3 라는 요소를 만들고 출력하고, 처리가 끝나면 종료된다.

1. lazy evaluation 이란 무엇인지와 장점

  • 일반적으로 range() 를 사용하여 임의의 숫자 list를 생성한다고 했을 때, 한 번의 실행으로 range() 함수 안에 지정된 숫자 만큼의 요소를 한 번에 생성하여 메모리에 저장한다.
  • 하지만 generator 는 전체 range()를 저장하는 것 대신에.. 요소를 만들어 내는 식을 저장해두고, 오직 필요할 때에만 다음의 값을 생성해는데, 이것을 lazy evaluation 이라고 한다.

list 표현식으로 만들어지는 것은 [0, 1, 2, 3...] 의 느낌.
제너레이터 표현식으로 만들어지는 것은 (i=0; i<10; i+=1) 의 느낌.

장점은, 당연히 메모리 효율이 좋을 것 같다.
한 번에 모든 데이터를 준비해두는 것 보다, 원할 때 원하는 값을 생성해서 다룰 수 있으니 메모리 효율에 좋을 것 같다.

2. 리스트 컴프리헨션과의 차이점에 대하여

  1. 리스트는 모든 요소를 그것이 생성될 때 저장한다. 하지만 제너레이터는 원할 때 그 다음의 요소를 생성한다.
  2. 리스트는 필요한 만큼 반복되어질 수 있지만, 제너레이터는 오직 한 번만 반복된다.
  3. 리스트는 인덱스로 요소를 추출할 수 있지만, 제너레이터는 인덱스를 사용할 수 없으며, 처음부터 끝까지 오직 값만 생성한다.

참고자료

profile
개발을 취미로 할 수 있는 그 때 까지

0개의 댓글