生成器与列表理解

时间:2013-11-12 15:52:44

标签: python generator list-comprehension

我有一些东西,当作为列表理解运行时,运行正常。

看起来像,

[myClass().Function(things) for things in biggerThing]

Function是一种方法,它会构建一个列表。该方法本身不会返回任何内容,但是列表会被操作。

现在当我将其更改为生成器时,

(myClass().Function(things) for things in biggerThing)

它不像我期望的那样操纵数据。事实上,它似乎根本没有操纵它。

列表理解生成器之间的功能区别是什么?

5 个答案:

答案 0 :(得分:5)

生成器会在消耗时进行动态评估。因此,如果您从不迭代生成器,则永远不会评估其元素。

所以,如果你这样做了:

for _ in (myClass().Function(things) for things in biggerThing):
    pass

Function会运行。


现在,你的意图在这里并不清楚。

相反,请考虑使用map

map(myClass().Function, biggerThing)  

请注意,这将始终使用MyClass的相同实例

如果这是一个问题,那么请执行:

for things in BiggerThing:
    myClass().Function(things)

答案 1 :(得分:3)

生成器是lazy evaluated。您需要处理生成器以便评估您的功能。可以使用collections.deque来使用生成器:

import collections
generator = (myClass().Function(thing) for thing in biggerThing) 
collections.deque(generator , maxlen=0)

并考虑使用@staticmethod@classmethod,或更改为

myfunc = myClass().Function
generator = (myfunc(thing) for thing in biggerThing) 
collections.deque(generator , maxlen=0)

为每个myClass处理减少thing创建的新实例。

更新,效果

  1. collections vs iteration
  2. def l():
        for x in range(100):
           y = x**2
          yield y
    
    def consume(it):
        for i in it:
            pass
    
    >>> timeit.timeit('from __main__ import l, consume; consume(l())', number=10000)
    0.4535369873046875
    >>> timeit.timeit('from __main__ import l, collections; collections.deque(l(), 0)', number=10000)
    0.24533605575561523
    
    1. 实例vs类与静态方法
    2. class Test(object):
          @staticmethod
          def stat_pow(x):
              return x**2
          @classmethod
          def class_pow(cls, x):
              return x**2
          def inst_pow(self, x):
              return x**2
      
      def static_gen():
          for x in range(100):
              yield Test.stat_pow(x)
      
      def class_gen():
          for x in range(100):
              yield Test.class_pow(x)
      
      def inst_gen():
          for x in range(100):
              yield Test().inst_pow(x)
      
      >>> timeit.timeit('from __main__ import static_gen as f, collections; collections.deque(f(), 0)', number=10000)
      0.5983021259307861
      >>> timeit.timeit('from __main__ import class_gen as f, collections; collections.deque(f(), 0)', number=10000)
      0.6772890090942383
      >>> timeit.timeit('from __main__ import inst_gen as f, collections; collections.deque(f(), 0)', number=10000)
      0.8273470401763916
      

答案 2 :(得分:2)

创建生成器时,您只能使用一次元素。这就像我正在创造一批我正在吃的饼干。他们服务于他们的目的(让我开心),但是一旦你使用它们就会消失。

列表推导创建列表,它们将允许您永久地(表面上)访问该数据结构。您还可以使用它们上的所有列表方法(非常有用)。但这个想法是它创建了一个实际的数据结构(为你保存数据的东西)。

点击这里的帖子:Generators vs. List Comprehensions

答案 3 :(得分:1)

生成器将不会执行该功能,直到您在生成器上调用next()

 >>>def f():
 ...    print 'Hello'
 >>>l = [f() for _ in range(3)]
 Hello
 Hello
 Hello
 >>>g = (f() for _ in range(3)) # nothing happens 
 >>>
 >>>next(g)
 Hello

答案 4 :(得分:0)

列表理解:

  • 列表可以编入索引。 例如。,。 [0, 1, 2, 3, 4][0]

  • 创建的列表可以使用任意次。

  • 空列表占用72个字节,每个项目添加占用8个字节。

发生器:

  • 生成器无法编入索引

  • 生成器只能使用一次。

  • 生成器占用的内存要少得多(80字节)。

请注意,对于生成器,一旦使用它,内部的内容就会被清空。

>>> sys.getsizeof([])
72
>>> list1 = [x for x in range(0, 5)]
>>> sys.getsizeof(list1)
136
>>>
>>> generator1 = (x for x in range(0,100))
>>> sys.getsizeof(generator1)
80
>>> generator1 = (x for x in range(0,5))
>>> sys.getsizeof(generator1)
80
>>> list(generator1)
[0, 1, 2, 3, 4]
>>> list(generator1)
[]
>>>