在python代码中,在哪里使用生成器特性?

在python代码中,在哪里使用生成器特性?,python,generator,Python,Generator,我已经研究了generators特性,我想我得到了它,但我想了解我可以在代码中应用它的地方 我在《Python基本参考》一书中读到了以下示例: 你有没有其他有效的例子,比如说生成器是像tail-f这样的工作的最佳工具 您多久使用一次生成器功能?您通常在程序的哪种功能\部分中应用它?当您的代码将生成无限数量的值时,或者更一般地说,如果最初生成整个列表将消耗太多内存时 或者,如果您可能没有迭代整个生成的列表(并且列表非常大)。我的意思是,如果不使用,那么首先生成每个值(并等待生成)是没有意义的 我最

我已经研究了generators特性,我想我得到了它,但我想了解我可以在代码中应用它的地方

我在《Python基本参考》一书中读到了以下示例:

你有没有其他有效的例子,比如说生成器是像tail-f这样的工作的最佳工具


您多久使用一次生成器功能?您通常在程序的哪种功能\部分中应用它?

当您的代码将生成无限数量的值时,或者更一般地说,如果最初生成整个列表将消耗太多内存时

或者,如果您可能没有迭代整个生成的列表(并且列表非常大)。我的意思是,如果不使用,那么首先生成每个值(并等待生成)是没有意义的


我最近一次遇到生成器是在我实现线性递归序列(LRS)时,比如斐波那契序列

我在实现扫描器(标记器)或迭代数据容器时经常使用它们

编辑:这里是C++语法高亮程序用的演示令牌:

whitespace = ' \t\r\n'
operators = '~!%^&*()-+=[]{};:\'"/?.,<>\\|'

def scan(s):
    "returns a token and a state/token id"
    words = {0:'', 1:'', 2:''} # normal, operator, whitespace
    state = 2 # I pick ws as first state
    for c in s:
        if c in operators:
            if state != 1:
                yield (words[state], state)
                words[state] = ''
            state = 1
            words[state] += c
        elif c in whitespace:
            if state != 2:
                yield (words[state], state)
                words[state] = ''
            state = 2
            words[state] += c
        else:
            if state != 0:
                yield (words[state], state)
                words[state] = ''
            state = 0
            words[state] += c
    yield (words[state], state)

通常,将数据获取(可能比较复杂)与消费分开。特别是:

  • 为了连接多个b-树查询的结果-db部分生成并执行查询
    yield
    -从每个查询中提取记录,使用者只看到单个数据项到达
  • 缓冲(预读)-生成器以块的形式获取数据,并从每个块生成单个元素。再一次,消费者被从血淋淋的细节中分离出来

生成器也可以作为协同程序工作。您可以使用“消费者”侧的
nextval=g.next(data)
和发电机侧的
data=yield(nextval)
将数据传递到它们。在这种情况下,生成器及其使用者“交换”值。您甚至可以在生成器上下文中使
yield
抛出一个异常:
g.throw(exc)
这样做。

在我有读取任何内容的算法的所有情况下,我都只使用生成器

为什么?

在多个生成器的上下文中,过滤、映射和简化规则的分层非常容易

例如:

def discard_blank( source ):
    for line in source:
        if len(line) == 0:
            continue
        yield line

def clean_end( source ):
    for line in source:
        yield line.rstrip()

def split_fields( source ):
    for line in source;
        yield line.split()

def convert_pos( tuple_source, position ):
    for line in tuple_source:
        yield line[:position]+int(line[position])+line[position+1:]

with open('somefile','r') as source:
    data= convert_pos( split_fields( discard_blank( clean_end( source ) ) ), 0 )
    total= 0
    for l in data:
        print l
        total += l[0]
    print total

我的偏好是使用许多小型生成器,这样一个小小的更改就不会破坏整个流程链。

你能发布一些简单的标记化器片段吗?@SystemPuntoot,好的,我发布了一个示例。请将此作为一个社区wiki问题。-1:听起来更像是对迭代器的一般描述,而不是生成器函数,所以它没有抓住要点。为什么这个答案得到了支持?@nikow:是的,它更一般,但我不会说它是对迭代器的描述。它是关于生成器在哪些情况下可能有用的抽象描述。生成器是某种迭代器……)因此,您只是使用生成器函数作为迭代器装饰器的方便符号。我认为Nick D的例子要好得多,因为它突出了连续性方面。@J.T.Hurley:我不知道“同样好”是什么意思,但生成器不会创建中间结果,而函数通常会创建中间结果。嵌套生成器是一种映射缩减管道。@nikow:我对连续体不感兴趣。我对将一个大的(可能是混乱的)操作分解成小的map reduce样式步骤很感兴趣。@S.Lott:Continuations是一个有趣的特性(特别是对于较新的协同程序功能),所以很遗憾您对它们不感兴趣;-)@尼科:就这个回答而言,我对它们不感兴趣。它们是一个有趣的特征。除了作为练习,我从来没有用过。我总是使用有状态的、可调用的对象,而不是continuations。但这超出了这个具体的答案。我的观点不是要涵盖发电机的所有可能用途。我的意思是回答这个问题:“任何其他有效的例子,其中发电机是工作的最佳工具”。
>>> it = scan('foo(); i++')
>>> it.next()
('', 2)
>>> it.next()
('foo', 0)
>>> it.next()
('();', 1)
>>> it.next()
(' ', 2)
>>> it.next()
('i', 0)
>>> it.next()
('++', 1)
>>> 
def discard_blank( source ):
    for line in source:
        if len(line) == 0:
            continue
        yield line

def clean_end( source ):
    for line in source:
        yield line.rstrip()

def split_fields( source ):
    for line in source;
        yield line.split()

def convert_pos( tuple_source, position ):
    for line in tuple_source:
        yield line[:position]+int(line[position])+line[position+1:]

with open('somefile','r') as source:
    data= convert_pos( split_fields( discard_blank( clean_end( source ) ) ), 0 )
    total= 0
    for l in data:
        print l
        total += l[0]
    print total