函数和生成器之间有什么区别?

6
我查看了这个问题https://stackoverflow.com/questions/29864146/difference-between-function-and-generator,但它被标记为重复。因此,我在这里发布我的答案版本。

原始问题是:

我正在寻找普通函数和生成器之间的确切区别。我已经谷歌搜索过了。但所有结果都很令人困惑。我是一个初学者,所以我希望有一些简短而精确的例子。

我尝试了这个What is the difference between normal function and generator function?,但没用。

我已经阅读了这个What does the "yield" keyword do?,但它纯粹是关于生成器的,没有关于函数和生成器之间的区别。我需要一些帮助吗?

1个回答

7
原则上,生成器由于其惰性求值而节省内存。
一个生成器非常类似于返回数组的函数,它具有参数、可以被调用,并生成一系列的值。但是,与构建包含所有值并立即返回它们的数组不同,生成器逐个yield值,这需要更少的内存,并允许调用者立即开始处理前几个值。
简而言之,生成器看起来像一个function,但行为像一个iterator
from itertools import count

itertools 提供了 count 方法,可以生成无限的整数流。你可以指定起始值和步长来生成这个流。下面是一个使用示例。

for i in count(start=0, step=1):    
    print i

一个生成偶数列表的简单示例。

构建并返回一个列表:

def find_even_number_function(number_stream):
    even_number = []
    for n in number_stream:
        if n % 2 == 0:
            even_number.append(n)
    return even_number

for i in find_even_number_function(count()):
    print i

这段代码非常简单和直接,但是它在内存中构建了完整的列表。在我们的情况下,这显然是不可接受的,因为我们无法承受将无限整数保存在内存中。正如你所看到的,该函数永远不会停止。在这种情况下,我们将使用生成器。

生成器使用yield来产生项目,而不是返回列表。

def find_even_number_generator(number_stream):
    for n in number_stream:
        if n % 2 == 0:
            yield n

for i in find_even_number_generator(count()):
    print i

请注意,数字生成逻辑的表达清晰自然。它非常类似于在内存中构建列表的实现,但具有迭代器实现的内存使用特性。
使用生成器带来的性能提升是惰性(按需)生成值的结果,这意味着内存使用更少。此外,我们不需要等到所有元素都被生成才开始使用它们。这类似于迭代器提供的好处,但生成器使构建迭代器变得容易。
因此,简单地说,如果您对上述情况使用普通函数,您将耗尽内存。或者,如果您使用生成器函数,则会耗尽时间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接