生成器推导是如何工作的?

140 投票
8 回答
91258 浏览
提问于 2025-04-11 20:35

生成器推导式是什么?它是怎么工作的?我找不到相关的教程。

8 个回答

7

列表/生成器推导是一种可以用来从现有列表或生成器创建新列表或生成器的方式。

假设你想生成从1到10每个数字的平方列表。你可以在Python中这样做:

>>> [x**2 for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

这里,range(1,11) 会生成列表 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],不过在Python 3.0之前,range 函数并不是生成器,所以我用的这个方法是列表推导。

如果我想创建一个做同样事情的生成器,我可以这样做:

>>> (x**2 for x in xrange(1,11))
<generator object at 0x7f0a79273488>

不过在Python 3中,range 就变成了一个生成器,所以结果只取决于你使用的语法(方括号或圆括号)。

38

生成器推导式是列表推导式的懒惰版。

它和列表推导式很像,只不过返回的是一个迭代器,而不是一个列表。也就是说,它返回的是一个有next()方法的对象,这个方法会给你下一个元素。

如果你对列表推导式不太熟悉,可以看看这里,而关于生成器的内容可以查看这里

204

你知道什么是列表推导式吗?如果知道的话,生成器表达式就像列表推导式,但它不是一次性把所有你感兴趣的东西都找出来放到一个列表里,而是一个一个地等着,把每个项目逐个输出。

>>> my_list = [1, 3, 5, 9, 2, 6]
>>> filtered_list = [item for item in my_list if item > 3]
>>> print(filtered_list)
[5, 9, 6]
>>> len(filtered_list)
3
>>> # compare to generator expression
... 
>>> filtered_gen = (item for item in my_list if item > 3)
>>> print(filtered_gen)  # notice it's a generator object
<generator object <genexpr> at 0x7f2ad75f89e0>
>>> len(filtered_gen) # So technically, it has no length
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'generator' has no len()
>>> # We extract each item out individually. We'll do it manually first.
... 
>>> next(filtered_gen)
5
>>> next(filtered_gen)
9
>>> next(filtered_gen)
6
>>> next(filtered_gen) # Should be all out of items and give an error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> # Yup, the generator is spent. No values for you!
... 
>>> # Let's prove it gives the same results as our list comprehension
... 
>>> filtered_gen = (item for item in my_list if item > 3)
>>> gen_to_list = list(filtered_gen)
>>> print(gen_to_list)
[5, 9, 6]
>>> filtered_list == gen_to_list
True
>>> 

因为生成器表达式一次只输出一个项目,所以它在内存使用上可以节省很多空间。生成器表达式特别适合那些你需要逐个处理项目、对每个项目进行大量计算,然后再处理下一个项目的场景。如果你需要多个值,也可以使用生成器表达式,一次获取几个。如果你在程序继续之前需要所有的值,那就用列表推导式。

撰写回答