yield表达式只能出现在函数中,当函数中含有yield表达式时,该函数被称作generator function,调用该函数并不执行该函数内的逻辑,而是返回generator对象。
generator对象支持的操作有:
- next
开始一个未执行的generator函数,或恢复执行一个在yield处挂起的generator函数
- send(value)
类似与next,但是可以传值value给generator函数,作为当前挂起的yield表达式的返回值,next等同于send(None)
- throw(type[, value[, traceback]])
在generator的挂起处抛出type类型的异常
- close()
在generator挂起处抛出GeneratorExit异常
generator只有在yield处才能挂起,将程序控制转给调用者;而调用者通过next/send也只能和在yield处挂起的generator进行交互。这就意味着控制权只能在generator和调用者之间轮换,而且是在yield处进行轮换,如果多个generator之间交换数据,那么只能通过主调者进行中转。
可以跟据yield是否返回值来讲generator分为两种:
- 不考虑yield返回值的generator,这种generator主要用来生成数据,供主调者使用;
- 考虑yield返回值的generator,可以看作是协程,可以接收主调者的数据进行处理,但这种协程如上所说,有很大的局限性。
一个协程的例子
def grep(pattern):
print "Looking for %s" % pattern
while True:
line = (yield)
if pattern in line:
print line,
# Example use
if __name__ == '__main__':
g = grep("python")
#must use next() or send(None) to prime it
g.next()
#after prime,it's ready to receive a value
g.send("Yeah, but no, but yeah, but no")
g.send("A series of tubes")
g.send("python generators rock!")
generator协程和greenlet的比较:
greenlet可以通过swith方法在同一线程的协程间自由切换,而generator只能在yield处进行切换,这就意味着如果有多个generator时,需要有主调者充当中转的角色。
参考
greenlet vs generator
coroutines
PEP 342 – Coroutines via Enhanced Generators
generator document
Generators Are Not Coroutines
the difference between generators, coroutines and continuations.