출처 : 윤성우의 열혈 파이썬 : 중급
09. generator 함수
- generator은 iterator 객체의 한 종류
- generator를 만드는 두가지 방법
- generator 함수(function)
- generator 표현식(expression)
함수 기반의 제너레이터
def gen_num():
print('first number')
yield 1
print('second number')
yield 2
print('third number')
yield 3
gen = gen_num() # generator 객체 생성
type(gen) # <class 'generator'>
next(gen) # first number \n 1
- gen_num이 일반 함수라면 그 안에 있는 모든 내용이 실행되나, 이 경우에는 하나도 실행되지 않는다
- 대신 'generator object'가 만들어져 반환된다
- generator object를 전달하며 next 함수를 호출하면 함수의 첫 번째 문장부터 시작해서 첫 번째 yield 문을 만날 때까지 실행을 이어간다
- 이 때 yield 는 return 의 역할을 하게되어 숫자 1을 반환
- 마지막 yield문이 실행되고 다시 next함수를 호출하면 StopIteration 예외 발생
- 이렇듯 함수 호출 이후에 그 실행의 흐름을 next 함수가 호출될 때까지 미루는(늦추는) 특성을 가리켜 lazy evaluation이라 한다
generator 함수 내 for 문
def gen_for():
for i in [1, 2, 3]:
yield i
g = gen_for()
next(g) # 1
next(g) # 2
next(g) # 3
제너레이터가 갖는 장점
def pows(s):
r = []
for i in s:
r.append(i ** 2)
return r
st = pows([1, 2, 3, 4, 5, 6, 7])
for i in st:
print(i, end = ' ')
import sys
sys.getsizeof(st) # 100
def gpows(s):
for i in s:
yield i ** 2
st = gpows([1, 2, 3, 4, h5, 6, 7])
for i in st:
print(i, end = ' ')
sys.getsizeof(st) # 64
- 위의 예에서 사용하는 메모리 공간의 크기는 리스트의 길이에 비례해서 늘어남
- 하지만 generator를 사용하는 경우 리스트의 길이에 상관 없이 사용하는 메모리의 공간의 크기가 동일
- generator object는 반환할 값들을 미리 만들어서 저장해 두지 않기 때문
생성되는 값들을 순서대로 하나씩 가져다 쓰면 되는 상황에서는 제너레이터를 기반으로 코드를 작성하는 것이 합리적
map & filter도 generator 함수이다
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
# 다음과 같이 간단히 쓸 수 있다
def get_nums():
ns = [0, 1, 0, 1, 0, 1]
yield from ns
g = get_nums()
next(g) # 0
next(g) # 1
'프로그래머 > Python' 카테고리의 다른 글
[윤성우의 열혈 파이썬 중급편] 11. 튜플의 패킹과 언패킹 (0) | 2020.12.15 |
---|---|
[윤성우의 열혈 파이썬 중급편] 10. generator 표현식 (0) | 2020.12.15 |
[윤성우의 열혈 파이썬 중급편] 07. map & filter (0) | 2020.12.15 |
[윤성우의 열혈 파이썬 중급편] 06. 객체처럼 다뤄지는 함수 그리고 람다 (0) | 2020.12.15 |
[윤성우의 열혈 파이썬 중급편] 05. Iterable 객체와 Iterator 객체 (0) | 2020.12.15 |