生成器理解如何工作?

问题描述 投票:0回答:8

生成器理解有什么作用?它是如何工作的?我找不到相关教程。

python generator generator-comprehension
8个回答
198
投票

你理解列表推导式吗?如果是这样,生成器表达式就像列表理解,但它不是查找您感兴趣的所有项目并将它们打包到列表中,而是等待,并从表达式中逐一生成每个项目。

>>> 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
>>> 

由于生成器表达式一次只需生成一项,因此可以大大节省内存使用量。在您需要一次获取一项、基于该项进行大量计算,然后继续处理下一项的情况下,生成器表达式最有意义。如果您需要多个值,您还可以使用生成器表达式并一次获取几个值。如果您在程序继续之前需要所有值,请使用列表理解。


37
投票

生成器理解是列表理解的惰性版本。

它就像列表理解一样,只不过它返回一个迭代器而不是列表,即带有 next() 方法的对象,该方法将产生下一个元素。

如果您不熟悉列表推导式,请参阅此处,对于生成器,请参阅此处


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]
,但
range
函数在Python 3.0之前不是生成器,因此我使用的构造是列表理解。

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

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

然而,在 Python 3 中,

range
是一个生成器,因此结果仅取决于您使用的语法(方括号或圆括号)。


5
投票

生成器理解是创建具有特定结构的生成器的简单方法。假设您想要一个

generator
来一一输出
your_list
中的所有偶数。如果你使用函数风格创建它,它会是这样的:

def allEvens( L ):
    for number in L:
        if number % 2 is 0:
            yield number

evens = allEvens( yourList )

您可以使用此生成器理解表达式获得相同的结果:

evens = ( number for number in your_list if number % 2 == 0 )

在这两种情况下,当您拨打

next(evens)
时,您会得到
your_list
中的下一个偶数。


2
投票

生成器理解是一种创建可迭代对象的方法,类似于在资源上移动的光标。如果您了解 mysql 游标或 mongodb 游标,您可能会意识到整个实际数据永远不会一次加载到内存中,而是一次加载一个。您的光标来回移动,但内存中始终有一行/列表元素。

简而言之,通过使用生成器理解,您可以轻松地在 python 中创建游标。


2
投票

生成器理解的另一个例子:

print 'Generator comprehensions'

def sq_num(n):
    for num in (x**2 for x in range(n)):    
        yield num

for x in sq_num(10):
    print x 

0
投票

生成器仅与列表相同,细微的区别在于,在列表中,我们一次获得列表中所有所需的数字或项目,但在生成器中,一次生成一个所需的数字。因此,为了获取所需的项目,我们必须使用 for 循环来获取所有必需的项目。

#to get all the even numbers in given range
 
def allevens(n):
    for x in range(2,n):
        if x%2==0:
            yield x

for x in allevens(10)
print(x)

#output
2
4
6
8

0
投票

我们可以将其理解为列表理解的生成器版本。在列表理解的情况下,我们使用单行代码或短代码创建一个,而对于生成器理解,我们为生成器创建单行代码或一小段代码。 它们具有相同的语法,只需将 [](方括号)替换为 () 大括号即可。

generator_composition_object = (num**3 for num in range(5))
print(generator_composition_object)

这将给出类型生成器的对象的地址。我们还可以在其中使用像 next() 这样的功能。

© www.soinside.com 2019 - 2024. All rights reserved.