何时使用Python中的生成器函数和何时使用循环?

8

我来自 Matlab,发现在 Python 中理解生成器的概念有些困难。

请问以下问题:

  1. 生成器函数和循环的区别
  2. 何时应该使用它们
2个回答

7

生成器提供了一种创建元素的方式,不需要在开始遍历之前将所有元素都保存在内存中。循环只是让生成器或其他可迭代对象逐个地返回元素。

例如:

for i in range(10):
    print(i)
for块是一个循环,range基本上是一个生成器。在循环开始之前,range不会创建1-10的列表,它只是创建了这些元素的生成器。你也可以想象一下range(1000000000000000000),因为在需要使用它们之前,没有任何元素被创建(而且不会占用内存),所以创建它也不需要时间。
另一方面,我们的循环也可以从已经存在的对象中获取一个元素,比如一个list
for i in [0,1,2,3,4,5,6,7,8,9]:
    print(i)

相同的结果会被打印出来,但是在循环开始之前会创建和存储整个列表。这意味着在循环运行时,列表需要占用内存空间和时间来创建。
两个例子都是循环,但只有第一个使用了生成器。
这只是基础知识,还有更多不同之处,例如可能引发的异常和可重复使用性,在部分迭代中以及其他方面。
欲了解更多关于差异的内容。
编辑:@Vicrobot指出range并不是真正的生成器,但为了简单起见,我使用了它来解释生成器的“惰性”。

2
范围不是生成器。https://dev59.com/_Wcs5IYBdhLWcg3wJglV#13092317 - Vicrobot
@Vicrobot,我已经添加了一个明确的编辑来澄清,这样我们就可以既客观又简单明了。 - Ofer Sadan
仅供参考:在MATLAB中,当它在for循环中时,1:1000的工作方式与Python的range完全相同。也就是说,MATLAB的for循环的工作方式与此处描述的两种模式完全相同。 - Cris Luengo

1
请阅读以下文章如何在Python中使用生成器和yield。也许以下示例可以帮助理解概念。
def my_range(n):
    for i in range(n):
        yield i

range_of_10 = my_range(10)
for i in range_of_ten:
    print(i)

result:

0
1
3
4
5
6
7
8
9

或者

>>> range_of_ten = my_range(10)
>>> next(range_of_ten)
0
>>> next(range_of_ten)
1
etc.
>>> next(range_of_ten)
9
>>> next(range_of_ten)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration


我喜欢下面的示例,您可以将双重循环替换为一个循环,如下所示:
def double_loop(n, m):
    for i in range(n):
        for j in range(m):
            yield i, j


n = double_loop(2, 4)
for i in n:
    print(i)

结果
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(1, 0)
(1, 1)
(1, 2)
(1, 3)

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