5

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

看起来像,

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

Function是一种方法,它建立一个列表。该方法本身不返回任何内容,但列表会在其中进行操作。

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

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

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

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

4

5 回答 5

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)
于 2013-11-12T15:54:23.130 回答
3

生成器是惰性求值的。您需要处理生成器才能评估您的功能。可以使用collections.deque一个生成器:

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

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

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

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

更新,性能

  1. collections对比iteration
定义 l():
    对于范围内的 x(100):
       y = x**2
      产量 y

定义消耗(它):
    因为我在里面:
        经过

>>> 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 类 vs 静态方法
类测试(对象):
    @静态方法
    def stat_pow(x):
        返回 x**2
    @classmethod
    def class_pow(cls, x):
        返回 x**2
    定义 inst_pow(自我,x):
        返回 x**2

def static_gen():
    对于范围内的 x(100):
        产量 Test.stat_pow(x)

定义类_gen():
    对于范围内的 x(100):
        产量 Test.class_pow(x)

定义 inst_gen():
    对于范围内的 x(100):
        产量测试().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
于 2013-11-12T15:56:57.193 回答
2

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

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

在这里查看这篇文章:生成器与列表理解

于 2013-11-12T15:56:33.687 回答
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
于 2013-11-12T16:00:38.633 回答
0

列表理解:

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

  • 一个创建的 List 可以使用任意次数。

  • 一个空列表占用 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)
[]
>>> 
于 2017-04-20T11:16:16.870 回答