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


当前回答

也适用于打印到n的质数:

def genprime(n=10):
    for num in range(3, n+1):
        for factor in range(2, num):
            if num%factor == 0:
                break
        else:
            yield(num)

for prime_num in genprime(100):
    print(prime_num)

其他回答

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

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

我发现生成器非常有助于清理代码,并为您提供了一种非常独特的方式来封装和模块化代码。如果您需要某些东西根据自己的内部处理不断地输出值,并且需要从代码中的任何地方调用该东西(而不仅仅是在循环或块中),则可以使用生成器。

一个抽象的例子是斐波那契数生成器,它不在循环中,当从任何地方调用它时,它总是返回序列中的下一个数字:

def fib():
    first = 0
    second = 1
    yield first
    yield second

    while 1:
        next = first + second
        yield next
        first = second
        second = next

fibgen1 = fib()
fibgen2 = fib()

现在你有了两个斐波那契数生成器对象,你可以在代码中的任何地方调用它们,它们总是会按如下顺序返回更大的斐波那契数:

>>> fibgen1.next(); fibgen1.next(); fibgen1.next(); fibgen1.next()
0
1
1
2
>>> fibgen2.next(); fibgen2.next()
0
1
>>> fibgen1.next(); fibgen1.next()
3
5

生成器的可爱之处在于,它们封装了状态,而不必经历创建对象的繁琐过程。考虑它们的一种方法是将它们视为记住其内部状态的“函数”。

我从Python生成器中得到了斐波那契函数的例子——它们是什么?只要有一点想象力,您就可以想出很多其他情况,在这些情况下,生成器可以很好地替代for循环和其他传统迭代结构。

简单的解释是: 考虑for语句

for item in iterable:
   do_stuff()

很多时候,iterable中的所有项都不需要从一开始就存在,但可以在需要时动态生成。这在两种情况下都更有效

空间(您永远不需要同时存储所有项目)和 时间(迭代可能在需要所有项目之前完成)。

其他时候,你甚至不知道所有的项目提前。例如:

for command in user_input():
   do_stuff_with(command)

你没有办法预先知道所有用户的命令,但如果你有一个生成器给你命令,你可以使用这样一个很好的循环:

def user_input():
    while True:
        wait_for_command()
        cmd = get_command()
        yield cmd

使用生成器,您还可以对无限序列进行迭代,这在迭代容器时当然是不可能的。

也适用于打印到n的质数:

def genprime(n=10):
    for num in range(3, n+1):
        for factor in range(2, num):
            if num%factor == 0:
                break
        else:
            yield(num)

for prime_num in genprime(100):
    print(prime_num)

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

返回

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()时,生成器都会从停止的地方恢复(它会记住所有数据值以及最后执行的语句)。