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