generator vs. list comprehension
我有一些东西,当作为列表理解运行时,运行良好。
看起来,
1 | [myClass().Function(things) for things in biggerThing] |
当我把它换成发电机时,
1 | (myClass().Function(things) for things in biggerThing) |
号
它不像我期望的那样操纵数据。事实上,它似乎根本无法操纵它。
列表理解和生成器之间的功能差异是什么?
发电机在使用过程中会被实时评估。因此,如果您从未在生成器上迭代,则不会对其元素进行计算。
所以,如果你这样做了:
1 2 | for _ in (myClass().Function(things) for things in biggerThing): pass |
现在,你的意图还不清楚。
相反,考虑使用
1 | map(myClass().Function, biggerThing) |
号
注意,这将始终使用MyClass的同一个实例
如果这是一个问题,那么做:
1 2 | for things in BiggerThing: myClass().Function(things) |
对生成器进行延迟评估。您需要处理一个生成器,以便对您的函数进行评估。可以使用
1 2 3 | import collections generator = (myClass().Function(thing) for thing in biggerThing) collections.deque(generator , maxlen=0) |
。
并考虑使用
1 2 3 | myfunc = myClass().Function generator = (myfunc(thing) for thing in biggerThing) collections.deque(generator , maxlen=0) |
减少每个
更新,性能
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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 |
。
创建生成器时,每个元素只能使用一次。就像我正在做一批饼干,我边吃边吃。它们满足它们的目的(让我高兴),但一旦你使用它们,它们就会消失。
列表理解创建列表,它们将允许您永久(表面上)访问该数据结构。您还可以使用上面的所有列表方法(非常有用)。但其想法是创建一个实际的数据结构(为您保存数据的东西)。
看看这篇文章:生成器与列表理解
在您调用生成器上的
1 2 3 4 5 6 7 8 9 10 | >>>def f(): ... print 'Hello' >>>l = [f() for _ in range(3)] Hello Hello Hello >>>g = (f() for _ in range(3)) # nothing happens >>> >>>next(g) Hello |
列表理解:
列表可以被索引。如。,。埃多克斯1〔10〕
创建的列表可以使用任意次数。
一个空列表占用72个字节,而对于每个项目的加法则额外占用8个字节。
发电机:
无法索引生成器
发电机只能使用一次。
生成器占用的内存要小得多(80字节)。
请注意,如果是生成器,一旦使用它,里面的内容就会被清空。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | >>> 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) [] >>> |
。