我开始学习Python,我遇到过生成器函数,其中有yield语句。我想知道这些函数最擅长解决什么类型的问题。


当前回答

缓冲。当以大块获取数据是有效的,但以小块处理数据时,生成器可能会有所帮助:

def bufferedFetch():
  while True:
     buffer = getBigChunkOfData()
     # insert some code to break on 'end of data'
     for i in buffer:    
          yield i

上面的方法可以让您轻松地将缓冲与处理分开。消费者函数现在可以一个一个地获取值,而不用担心缓冲。

其他回答

请参阅PEP 255中的“动机”部分。

生成器的一个不太明显的用途是创建可中断函数,它允许您在不使用线程的情况下“同时”执行更新UI或运行多个作业(实际上是交错的)。

我发现这个解释消除了我的疑虑。因为有一种可能,不知道发电机的人也不知道产量

返回

return语句是销毁所有局部变量并将结果值返回(返回)给调用者的语句。如果同一函数稍后被调用,该函数将获得一组新的变量。

收益率

但是,如果退出函数时局部变量没有被丢弃呢?这意味着我们可以从中断的地方恢复函数。这是引入生成器概念的地方,yield语句从函数停止的地方恢复。

  def generate_integers(N):
    for i in xrange(N):
    yield i

    In [1]: gen = generate_integers(3)
    In [2]: gen
    <generator object at 0x8117f90>
    In [3]: gen.next()
    0
    In [4]: gen.next()
    1
    In [5]: gen.next()

这就是Python中return语句和yield语句的区别。

Yield语句使函数成为生成器函数。

因此生成器是创建迭代器的简单而强大的工具。它们像常规函数一样编写,但它们在想要返回数据时使用yield语句。每次调用next()时,生成器都会从停止的地方恢复(它会记住所有数据值以及最后执行的语句)。

基本上避免回调函数时迭代输入维护状态。

请参阅这里和这里,了解使用生成器可以做什么。

我最喜欢的用法是“过滤”和“减少”操作。

假设我们正在读取一个文件,并且只想要以“##”开头的行。

def filter2sharps( aSequence ):
    for l in aSequence:
        if l.startswith("##"):
            yield l

然后,我们可以在适当的循环中使用生成器函数

source= file( ... )
for line in filter2sharps( source.readlines() ):
    print line
source.close()

reduce的例子类似。假设我们有一个文件,其中我们需要定位<Location>…< / >位置线。[不是HTML标签,而是恰好看起来像标签的行。]

def reduceLocation( aSequence ):
    keep= False
    block= None
    for line in aSequence:
        if line.startswith("</Location"):
            block.append( line )
            yield block
            block= None
            keep= False
        elif line.startsWith("<Location"):
            block= [ line ]
            keep= True
        elif keep:
            block.append( line )
        else:
            pass
    if block is not None:
        yield block # A partial block, icky

同样,我们可以在一个合适的for循环中使用这个生成器。

source = file( ... )
for b in reduceLocation( source.readlines() ):
    print b
source.close()

其思想是,生成器函数允许我们过滤或减少序列,每次生成一个值的另一个序列。

当我们的web服务器充当代理时,我使用生成器:

客户端从服务器请求一个代理url 服务器开始加载目标url 服务器在获得结果后立即将结果返回给客户机