티스토리 뷰

728x90
반응형

제너레이터

제너레이터는 루프의 반복 동작을 제어할 수 있는 루틴 형태를 말한다. 예를 들어 임의의 조건으로 숫자 1억 개를 만들어내 계산하는 프로그램을 작성한다고 가정해보자. 이 경우 제너레이터가 없다면 메모리 어딘가에 만들어낸 숫자 1억 개를 보관하고 있어야 하낟. 그러나 제너레이터를 이용하면, 단순히 제너레이터만 생성해두고 필요할 때 언제든 숫자를 만들어낼 수 있다.

이때 yield 구문을 사용하면 제너레이터를 리턴할 수 있다. 기조느이 함수는 return 구문을 맞닥뜨리면 값을 리턴하고 모든 함수의 동작을 종료한다. 그러나 yield는 제너레이터가 여기까지 실행 중이던 값을 내보낸다는 의미로, 중간 값을 리턴한 다음 함수는 종료되지 않고 계속해서 맨 끝에 도달할 때까지 실행된다.

yield의 값을 확인하려면 next()로 추출하면 된다. 예를 들어 100개의 값을 생성하고 싶다면 다음과 같이 100번 동안 next()를 수행하면 된다.

def get_natural_number():
    n = 0
    while True: 
        n += 1
        yield n

g = get_natural_number()
for _ in range(0, 100):
    print(next(g))

range

range()는 range 클래스를 리턴하며, for 문에서 사용할 경우 내부적으로는 제너레이터의 next()를 호출하듯 매번 다음 숫자를 생성해내게 괸다.

만약 생성할 숫자가 100만 개쯤 된다면 어떻게 될까? 메모리에서 적지 않은 공간을 차지할 것이고 생성 시간도 오래 걸릴 것이다. 그러나 제너레이터를 리턴하듯 range 클래스만 리턴하면 그렇지 않다. 생성 조건만 정해두고 나중에 필요할 때 생성해서 꺼내 쓸 수 있다. 다음은 숫자 100만개를 생성하는 2가지 방법이다.

import sys

a = [n for n in range(1000000)]
b = range(1000000)

print(type(a))
print(type(b))

print(sys.getsizeof(a))
print(sys.getsizeof(b))

"""
<class 'list'>
<class 'range'>
8697456
48
"""

a에는 이미 생성된 값이 담겨 있고, b는 생성해야 한다는 조건만 존재한다. 똑같이 숫자 100만 개를 갖고 있으나 range 클래스를 이용하는 b 변수의 메모리 점유율이 훨씬 더 작다. b 변수는 생성 조건만 보관하고 있기 때문이다.




출처
파이썬 알고리즘 인터뷰 (글 : 박상길 그림 : 정진호) [책만]

728x90
반응형
댓글
반응형
250x250
글 보관함
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Total
Today
Yesterday
링크