Python에서 함수와 유사한 형태를 가졌으나, 함수와 구별되는 개념이 하나 있는데, 이것이 바로 Generator이다.
Generator 역시 일종의 함수이지만, 일반적인 함수와 달리 iterator(이터레이터, 반복자)를 리턴한다. 이때 iterator이란, iterable 객체를 순회 탐색하는 객체를 말한다. 즉 iterable의 원소를 가리키는 커서와 같은 역할을 한다. generator은 return 대신에 'yield(양보하다)'라는 구문으로 iterator을 리턴하는데, generator의 동작 원리에 대해서는 아래의 코드를 통해 살펴보자.
def generator_ex():
times = 1
while True:
yield times
times += 1
gen = generator_ex()
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
먼저 generator을 호출하기 위해서는 next(generator) 함수를 사용한다. 일반적인 함수에서 함수 이름과 인자만으로 함수를 호출하는 것과는 다르다.
위의 코드는 얼핏 보면 무한루프에 빠질 것만 같다. 실제로 일반적인 함수 구문이면 그렇다. 하지만 generator에서는 그렇지 않은데, 이 코드의 동작 방식에 대해 살펴보자.
generator의 동작 규칙은 다음과 같다.
1. 처음으로 next 함수가 호출되면, 해당 generator를 실행한 후 yield 구문을 실행하면 멈춘다.
2. 이후 next 함수가 호출되면, yield 구문 다음부터 generator를 실행하여 다음 yield 구문을 실행하면 멈춘다.
3. yield 구문을 만나지 않고 generator가 종료되는 경우, StopIteration 에러를 발생시킨다.
즉 매 호출마다 yield 구문까지 실행하는 것이다. 이때 generator가 호출된 이후 다음 호출때까지 generator의 내부 변수들과 실행 상태가 저장되어 있으므로 위의 규칙에 의한 동작이 가능하다. 그러면 이를 통해 위의 코드를 해석해 보자.
우선 generator_ex 를 gen이라는 객체에 저장하고, next 함수를 통해 generator의 iterator를 호출한다.
첫 번째 호출 때에는 times에 1을 저장하고, times 값을 yield 하므로 1이 리턴된다. generator는 여기서 잠시 멈춘다.
두 번째 호출 때에는 generator가 yield times 다음부터 동작하여, times에 1을 더하고 다시 times 값을 리턴한다. 즉 2를 리턴하게 된다.
세 번째 호출 때에도 generator가 yield times 다음부터 동작하여, times에 1을 더하고 다시 times 값을 리턴한다. 즉 3을 리턴하게 된다.
따라서 한 번의 호출로 무한 루프가 도는 것이 아니라, generator를 생성할 때마다 한 바퀴씩, 무한정 돌 수 있는 것이다.
또한 generator를 여러 개 생성하는 경우, 같은 generator 함수에 의한 생성이라고 해도 다른 객체에서 서로 독립적으로 동작한다.
def generator_ex():
times = 1
while True:
yield times
times += 1
gen1 = generator_ex()
gen2 = generator_ex()
print(next(gen1)) # 1
print(next(gen1)) # 2
print(next(gen2)) # 3 아니고 1
레퍼런스
'파이썬(Python) > 문법 내용정리' 카테고리의 다른 글
Collections 모듈 - Counter (0) | 2021.01.31 |
---|---|
Type Hint (타입 힌트) (0) | 2021.01.29 |
F-string (가장 강력한 print 방법) (0) | 2021.01.28 |
Enumerate 함수 (0) | 2021.01.27 |
Comprehension (List, Set, Dict) (0) | 2021.01.24 |
댓글