生成器理解究竟是如何工作的?

时间:2008-12-13 03:55:45

标签: python

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

7 个答案:

答案 0 :(得分:123)

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

python2版本:

>>> 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 at 0xb7d5e02c>
>>> 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.
... 
>>> filtered_gen.next()
5
>>> filtered_gen.next()
9
>>> filtered_gen.next()
6
>>> filtered_gen.next() # 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
>>> 

python3版本:

next()更改为__next__()

因为生成器表达式一次只能生成一个项目,所以可以大大节省内存使用量。在需要一次取一个项目,根据该项目进行大量计算,然后转到下一个项目的情况下,生成器表达式最有意义。如果您需要多个值,您还可以使用生成器表达式并一次抓取一些。如果在程序开始之前需要所有值,请改用列表推导。

答案 1 :(得分:16)

生成器理解是列表推导的懒惰版本。

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

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

答案 2 :(得分:4)

列表/生成器理解是一种可用于从现有列表/生成器创建新列表/生成器的构造。

假设您要生成从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是一个生成器,因此结果仅取决于您使用的语法(方括号或圆括号)。

答案 3 :(得分:2)

生成器理解是创建具有特定结构的生成器的简单方法。假设您希望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中获得下一个偶数。

答案 4 :(得分: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

答案 5 :(得分:0)

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

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 

答案 6 :(得分:0)

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

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