흔하지 않은 컨셉이기는 하나 느긋함(lazyness)이라는 컨셉은 코드를 바라보는 시각을 크게 바꿀 수 있는 중요한 지점이 될 수 있다. 이 글에서는 파이썬에서 느긋함이란 무엇이며, 파이썬에서는 어떻게 적용되는지, 그리고 이 컨셉을 통해서 기존 코드를 어떤식으로 개선할 수 있는지에 대해 살펴보도록 하겠다. 다음은 이 글의 내용과 예제 코드를 이해하는데 필요한 몇 가지 사전 정보이다.
파이썬은 처음이라 – 느긋하긴 처음이라 더보기Tag: Generator
파이썬 yield from – 다른 코루틴에게 작업을 위임하기
파이썬에선 함수 내부에 yield
키워드가 쓰였다면 이는 일반적인 함수가 아니라 제너레이터를 만드는 제너레이터 함수(혹은 코루틴 함수)가 된다. 제너레이터는 next()
함수를 통해서 생성하는 값을 꺼낼 수 있고, 동시에 .send()
메소드를 써서 그 내부로 값을 전달할 수 있다. 특히 이렇게 값을 주입해 줄 수 있는 제너레이터를 코루틴이라 한다고 했다.
코루틴 혹은 제너레이터의 내부에서 다른 코루틴이나 제너레이터의 결과값을 그대로 사용하는 경우가 있을 수 있다. 예를 들어 다음의 경우, 주어진 값으로부터 1씩 내렸다가 다시 0부터 n-1까지 값을 생성하는 제너레이터가 있다고 하자.
def foo(n):
for i in range(n, 0, -1):
yield i
for i in range(n):
yield i
list(foo(5))
# -> [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
이렇게 제너레이터 내부에서 다른 제너레이터의 결과를 사용하는 경우에 yield from
으로 코드를 간결하게 만들 수 있다.
def foo(n):
yield from range(n, 0, -1)
yield from range(n)
사실 yield from
은 실용적인 맥락에서는 별로 쓰일일이 없다. Python 3.5에서 비동기 코루틴의 결과를 기다리는 await
문이 추가되기 전에 같은 기능을 위한 문법으로 추가된 것이기 때문이다.
yield from
이 작동하는 방식은 간단하다. 제너레이터/코루틴 내부에서 다른 제너레이터/코루틴에 대해서 yield from subcoroutine()
을 사용하는 것이다.
- 이 경우 해당 코루틴에 대해
next(co)
,co.send(v)
를 호출하는 것은 곧장subcoroutine()
의 동작으로 연결되며,co
내부의yield from
지점에서는 코드가 진행되지 않는다. - 서브코루틴이 동작을 완료하여
StopIteration
예외를 일으키면yield from
구문이 종료되고 다음 라인으로 실행 흐름이 이동한다.
yield from
을 사용하여 작업을 위임하는 경우, next()
와 send()
가 동일하게 위임된다. 차이가 있다면 next()
가 send(None)
과 똑같이 동작하게 된다는 것이다.
다음은 해당 기능을 설명한 PEP380에 등장하는 예제이다. 누계를 받아서 리턴해주는 acc()
코루틴을 사용해서 여러 수열의 누적합을 만드는 예이다. 유용할지는 모르지만, 작업 위임이 어떤식으로 동작하는지는 볼 수 있는 예이다.
def acc():
s = 0
while True:
n = yield s
if n is None:
return s
s += n
@coroutine
def gather(xs):
while True:
subtotal = yield from acc()
xs.append(subtotal)
ns = []
g = gather(ns)
g.sender(10) # -> 10
g.sender(20) # -> 30
g.sender(30) # -> 60
next(g)
# ns = [60]
제너레이터 타입검사 (파이썬)
[[코루틴과 병렬처리]]에서 잠깐 다뤘지만, 제너레이터 타입인지를 검사하기 위해서는 types
모듈의 GeneratorType
클래스를 이용하면 된다.
someGenerator = someGeneratorFunc()
import types
isassert isinstance(someGenerator, types.GeneratorType)