【问题标题】:How exactly does a generator comprehension work?生成器理解究竟是如何工作的?
【发布时间】:2010-09-26 18:14:58
【问题描述】:

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

【问题讨论】:

标签: python


【解决方案1】:

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

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

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

【讨论】:

  • 这里有一个问题。我使用 next(gen_name) 来获得结果,它在 Python 3 中工作。有没有我们需要使用 __next__() 的特定场景?
  • @AnkitVashistha 不,在 Python 3 中始终使用 next(...) 而不是 .__next__()
  • @gotgenes @AnkitVashistha If you need more than one value, you can also use a generator expression and grab a few at a time。你能举一个关于这种用法的例子吗?谢谢。
【解决方案2】:

生成器推导是列表推导的惰性版本。

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

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

【讨论】:

  • A generator comprehension is the lazy version of a list comprehension 可能是我读过的最好的单行解释之一。谢谢!
  • 耶!我很高兴你发现它有帮助! :)
【解决方案3】:

列表/生成器理解是一种构造,您可以使用它从现有列表/生成器创建新的列表/生成器。

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

【讨论】:

  • 这是错误的。外部表达式是否是生成器与内部表达式是否是无关的。虽然很明显,生成器表达式从列表中获取元素通常没有多大意义,但您可以这样做。
  • 这个可以改写更清楚吗?我明白你在说什么,但正如锑所说,看起来你在说别的东西。 (看起来你说的是错误的)
【解决方案4】:

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

【讨论】:

    【解决方案5】:

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

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

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

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

      【讨论】:

        【解决方案7】:

        生成器仅与列表相同,细微的区别在于,在列表中,我们得到所有需要的数字或列表中的项目,但在生成器中,所需的数字一次生成一个。因此,为了获取所需的项目,我们必须使用 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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-10-07
          • 2021-06-18
          • 2011-06-26
          • 2021-08-15
          • 2012-06-08
          • 2011-10-11
          • 2013-07-05
          • 1970-01-01
          相关资源
          最近更新 更多