Python TIL(8) - Generator

random·2021년 4월 1일
0

Python - TIL

목록 보기
8/19

Generator 탐구하기

대량의 값을 다루어야 할 때 유용한 Generator를 학습해보자.

  • Generator의 정의: 주어진 함수의 반환값을 하나씩 그때 그때 필요시마다 발생시키는 역할을 한다.
  • 특징1. 메모리 휘발성: generator는 값을 넘겨주고(소비하고) 그 해당값을 메모리에서 지운다. 즉, 이전값에 대한 정보가 사라지게 된다.
    => 따라서, 대규모 리스트를 만들어서 메모리를 잡아먹는 것이 불필요 할때, 메모리 효율 측면에서 높은 성능이 필요시 될 때 사용하면 용이하다.
    => 예시: 1에서 100000까지의 숫자 리스트를 만드는데 두가지 방법 사용 가능: (1) for loop 제너레이터를 만들어서 예를 들어 1~4까지 만들게 하고 같은 행동을 반복하게 하는 제너레이터를 발동시켜서 픽업을 하거나, (2) 1~100000까지 엄청 큰 리스트를 만드는 for loop을 실행해서 메모리상 하나하나 픽업 하는 것임.
  • 특징2. 특정 계산이 필요할 때까지 대기하는 성질: 제너레이터는 기본적으로 yield 키워드의 기능을 수행하며 이는 iterating 될 때 for 문처럼 전체값을 한 번에 반환하는게 아니라; 값 하나를 반환하고 대기상태에 머물며 다음 명령을 기다리는 특징을 지닌다. 따라서 수행 시간이 긴 연산을 필요한 순간까지 늦출 수 있다는 점이 특징이 있다.
    *Yield와 return의 차이점: yield는 return과 동일한 기능을 수행하는데, 단 한가지 차이점이 있다면 return 처럼 하나의 값을 반환하는 것이 아니라 제네레이터 객체를 반환한다.

<제너레이터 실습을 위한 피보나치 수열 코드>

def gen_fibon(n):

    a = 1
    b = 1
    for i in range(n):
        yield a
        a, b = b, a+b

for number in gen_fibon(10):   
    print(number)
  • 위 코드의 출력값:

    1
    2
    3
    5
    8
    13
    21
    34
    55

  • 위 예제 코드를 gen_fibon 함수 단독으로만 실행하면 그저 자신의 객체만을 반환하게된다. 함수 내부의 해당 코드는 추후 실제로 for 루프로 제너레이터를 돌릴 때 실행된다.

  • 함수로부터 만들어진 제너레이터 객체가 for 루프를 통해 처음 실행될 때, Python은 함수 내에 있는 코드를 yield 키워드를 만나기 전까지 실행하고 첫 번째 루프의 값을 반환한다. 다음 루프 때에는 yield 키워드 뒤에 있는 코드를 실행하고 다시 루프를 돌면서 반환할 값이 모두 소진되어 없을때까지 계속 같은 과정을 반복하게 된다.

  • 모든 값에 대한 반환이 완료되면 iteration이 종료된다. 모든 값은 단 한번만 순회한다는 특징을 지닌다.


<Yield의 대기하는 성질을 보여주는 코드>

#1번 예제

def simple_gen():
    for x in range(3):
        yield x   
for number in simple_gen():
    print(number)

g = simple_gen()  
print(next(g)) #출력값: 0
print(next(g)) #출력값: 1
print(next(g)) #출력값: 2 이후 프로그램 종료
  • 변수 g를 통해서 simple_gen() 함수를 실행하면 출력값은 for문의 루핑을 통해 0, 1, 2가 나오게 된다.
  • 이 때, for문이 아닌 next(g) 메소드를 의도적으로 넣어 봄으로써; 한 번에 모든 값이 반환되지 않고 0, 1, 2에 대한 순차적인 출력 명령이 있어야지만 다음 출력 명령으로 넘어가는 Generator + Yield의 (대기하는) 특징을 확인 할 수 있다.

# 2번 예제

s = 'hello'
# for letter in s:
#     print(letter) 

s_iter = iter(s)
print(next(s_iter)) #h
print(next(s_iter)) #e
print(next(s_iter)) #l
print(next(s_iter)) #l
print(next(s_iter)) #o
  • next(s) 위에 int타입에서 통하던 이터레이션이 여기 str타입에선 적용이 안됨. 따라서 str타입에서 이터레이션을 쓰려면 특별히 이터레이션을 첨가해주는 iter(s) 메소드를 사용해야함.
  • next() 메소드의 영향으로 위 1번 예제의 출력값처럼 2번 예제도 문자열 출력값이 h, e, l, l, o하나씩 반환되는 결과를 보인다.

0개의 댓글