在很多情况下,人们总是说“使用 yield
来延迟创建元素”。
但我认为一切都有成本,包括 yield
及其迭代器。
在 effective nord 眼中,我认为这是一个很好的问题。 所以,例如,当我得到一个函数时。
def list_gen(n):
if n > MAGIC_NUM:
return xrange(n)
else:
return range(n)
MAGIC_NUM 是多少剂量?
更新 对这个错误感到抱歉,我的意思是比较迭代器的成本和列表成本。
再次更新 请想象一个案例。是否有一个条件,即内存限制到无法创建迭代器。
哈,这个问题现在更有趣了。
再次更新 为什么创建一个迭代器和保存 yield 上下文比创建一个列表少?或迭代器的成本是多少?(对不起我的侮辱)多少字节?
最佳答案
你把几件事混在一起了。
def list_gen(n):
i=0
while i<n:
yield i
i += 1
这个函数是一个生成器。调用它会返回一个生成器对象,它是一个迭代器。
迭代器是具有next()
的东西,即它可以被遍历一次。每当您执行 for i in something
时,都会使用 iter
在某些内容上创建迭代器。
def list_gen(n):
return range(n)
def list_gen(n):
return xrange(n)
这些函数是常规函数。一个返回一个 list
,另一个返回一个 xrange
对象。列表和 xranges 都是可迭代的,即可以为它们创建多个独立的迭代器。
回到你的问题:你问的是返回一个 list
还是一个 xrange
对象。
这显然取决于!这取决于您要对结果做什么。
如果您想以某种方式改变它,那么您需要一个真实的列表。直接使用
range
。如果您只想迭代它,那么它在语义上没有区别:
xrange
对象和list
返回的>range
将生成迭代相同序列的迭代器。但是,如果您使用
xrange
,您将永远不会在内存中创建整个列表。如果您只想进行简单的迭代,为什么还要在内存中创建一个完整的list
对象?您不需要在需要for
循环时分配临时大内存缓冲区,对吧?
因此:坚持使用 xrange
是安全的,因为调用者总是可以从中创建一个 list
。
让我们用一个基准来确认这一点。我们想知道遍历 xranges 是否比遍历由 range
构造的列表更快(当然包括 range
调用的成本)。
代码:
import timeit
ns = [1,2,3, 5, 10, 50, 100]
print 'n', '\t', 'range', '\t', 'xrange'
for n in ns:
t1 = timeit.timeit("for i in range({}): pass".format(n))
t2 = timeit.timeit("for i in xrange({}): pass".format(n))
print n, '\t', t1, '\t', t2
结果:
n range xrange
1 0.566222990493 0.418698436395
2 0.594136874362 0.477882061758
3 0.630704800817 0.488603362929
5 0.725149288913 0.540597548519
10 0.90297752809 0.687031507818
50 2.44493085566 1.89102105759
100 4.31189321914 3.33713522433
关于python - 在 Python 中,当 yield cost 超过返回列表时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13622551/