2

我正在做一些测试,发现这比(各种问题/答案也证实了)xrange()快得多:range()

>>> from timeit import timeit
>>> timeit(stmt = 'x = range(1000)', number = 10000)
0.38216601211680734
>>> timeit(stmt = 'x = xrange(1000)', number = 10000)
0.010537726631953959 # xrange is much faster than range

我很好奇,所以我尝试了另一个测试,看看是否list(xrange(1000))仍然比简单的更快range(1000)

>>> timeit(stmt = 'x = range(1000)', number = 10000)
0.3858838963796529
>>> timeit(stmt = 'x = list(xrange(1000))', number = 10000)
0.492734766028903 # now, xrange is slower

对于更多调用也是如此:

>>> timeit(stmt = 'x = range(1000)', number = 100000)
3.6457308233315757
>>> timeit(stmt = 'x = list(xrange(1000))', number = 100000)
5.722031755612818

所以,我的问题是,为什么比它本身list(xrange)慢得多range

我在 , 和其他构造函数方法的缓慢性上看到了这个问题list()dict()那为什么list(xrange)这么慢?

使用dis.dis(),我发现list(xrange)执行的计算量比range) 多:

>>> dis.dis('x = list(xrange(1000))')
          0 SETUP_LOOP      15648 (to 15651)
          3 SLICE+2        
          4 IMPORT_NAME     29545 (29545)
          7 LOAD_GLOBAL     30760 (30760)
         10 POP_JUMP_IF_FALSE 28257
         13 BUILD_LIST      10341
         16 <49>           
         17 <48>           
         18 <48>           
         19 <48>           
         20 STORE_SLICE+1  
         21 STORE_SLICE+1  
>>> dis.dis('x = range(1000)')
          0 SETUP_LOOP      15648 (to 15651)
          3 SLICE+2        
          4 POP_JUMP_IF_FALSE 28257
          7 BUILD_LIST      10341
         10 <49>           
         11 <48>           
         12 <48>           
         13 <48>           
         14 STORE_SLICE+1  
4

2 回答 2

6

当然range()会更快,当您想要的最终产品是一个范围内所有数字的列表时,所有这些range都在一个函数调用中完成。与之相反,list(xrange())构造函数需要承担为迭代对象而创建list(..)的对象的开销,而构造函数必须消耗这些开销。而立即构造列表,没有中间迭代器消耗......怎么能被打败?主要区别在于:1 个函数调用 vs 2 个,次要的 1 个全局查找 vs 2 个。rangeiteratorxrangelist(..)range()

于 2013-04-27T13:27:46.013 回答
2

range()将立即构建一个列表并将其返回给您。因此,如果它有很多项目,则构建速度很慢。

另一方面,xrange()直接返回一个类似迭代器的对象,当您请求它们时会产生值。从文档:

xrange(start, stop[, step])
此函数与 range() 非常相似,但返回的是xrange对象而不是列表。这是一种不透明的序列类型,它产生与相应列表相同的值,但实际上并没有同时存储它们。xrange()over的优势range()是最小的(因为xrange()仍然必须在被要求时创建值),除非在内存不足的机器上使用非常大的范围或从不使用范围的所有元素(例如当循环通常以 break 结束)。

所以,在你的第一个例子中,xrange()自然更快,而在第二个例子中它更慢,因为虽然range()已经返回一个列表(那时不会被转换),list(xrange())但必须做更多的工作来不仅产生值,而且创建一个新列表并将值存储在其中。

PS 这适用于 Python 2。相反,在 Python 3 中,只有range()与 Python 2- 完全一样的工作xrange()

于 2013-04-27T13:28:05.003 回答