Python generator的基本能力如何?以generator方式实现了一个斐波那契数列生成函数,

def fib(n):
  if n <= 0:
    raise StopIteration
  i = 0
  a = 1
  b = 1
  while i < n:
    if i < 2:
      yield 1
    else:
      v = a + b
      yield v
      a = b
      b = v
    i += 1

# for .. in方式调用
>>> for x in fib(5): print x
...
1
1
2
3
5

# next方式单步调用
>>> x = fib(5)
>>> print x.next()
1
>>> print x.next()
1
>>> print x.next()
2
>>> print x.next()
3
>>> print x.next()
5

从上述代码中可以看到generator的语法规则,通过yield返回数据,外层代码通过next调用触发执行yield之后的代码逻辑。当不存在可执行逻辑时会抛出StopIteration异常。在yield、next()、StopIteration之外,还有send()函数,

def foo(n):
  x = 0
  for i in xrange(n):
    x = yield x

>>> x = foo(10)
>>> x.next()
0
>>> x.send(3)
3
>>> x.send(5)
5

send()函数可以向generator发送数据,作为yield语句的返回值。

从这两个例子中可以看到generator帮助进行了状态维护,以此让连续代码片段分段执行的能力。在实际中如何应用generator的特性?当然有不少开源项目充分利用了generator,但在具体实际开发中有哪些部分可以直接利用generator而无需引入外界框架呢?

目前遇到的可能合适场景有,

  • 资源的分块缓存加载

    在加载完部分资源之后调用yield,等待外界调用next再次加载。通过generator维护加载完成状态。

  • 异步代码同步化实现

# 异步callback执行方式

def foo():
  ...
  do_something_a(lambda data: complete_do_something_a(data))

def complete_do_something_a(data):
  ...
  do_something_b(lambda data: complete_do_something_b(data))

def complete_do_something_b(data):
  ...

# generator方式执行

def foo():
  data = yield do_something_a()
  yield do_something_b(data)

以generator方式来组织代码还需要外层实现一套简单的调度代码,可以根据具体实现复杂情况来考虑是否选择。