Python中的生成器和yield详细介绍

2019-10-05 11:17:07于丽

协程的运行一般是无限期的,使用方法close()可以显式的关闭它。

如果yield表达式中提供了值,协程可以使用yield语句同时接收和发出返回值。

def split_line():
    print 'ready to split'
    result=None
    while True:
        line=yield result
        result=line.split()
>>> s=split_line()
>>> s.next()
ready to split
>>> s.send('1 2 3')
['1', '2', '3']
>>> s.send('a b c')
['a', 'b', 'c']

注意:理解这个例子中的先后顺序非常重要。首个next()方法让协程执行到yield result,这将返回result的值None。在接下来的send()调用中,接收到的值被放到line中并拆分到result中。send()方法的返回值就是下一条yield语句的值。也就是说,send()方法可以将一个值传递给yield表达式,但是其返回值来自下一个yield表达式,而不是接收send()传递的值的yield表达式。

如果你想用send()方法来开启协程的执行,必须先send一个None值,因为这时候是没有yield语句来接受值的,否则就会抛出异常。

>>> s=split_line()
>>> s.send('1 2 3')
TypeError: can't send non-None value to a just-started generator
>>> s=split_line()
>>> s.send(None)
ready to split

使用生成器与协程

乍看之下,如何使用生成器和协程解决实际问题似乎并不明显。但在解决系统、网络和分布式计算方面的某些问题时,生成器和协程特别有用。实际上,yield已经成为Python最强大的关键字之一。

比如,要建立一个处理文件的管道:

import os,sys
def default_next(func):
    def start(*args,**kwargs):
        f=func(*args,**kwargs)
        f.next()
        return f
    return start
@default_next
def find_files(target):
    topdir=yield
    while True:
        for path,dirname,filelist in os.walk(topdir):
            for filename in filelist:
                target.send(os.path.join(path,filename))

@default_next
def opener(target):
    while True:
        name=yield
        f=open(name)
        target.send(f)
   
@default_next