为什么Python3中没有xrange函数?

最近我开始使用Python3,它缺乏xrange的伤害。

简单的例子:

1) Python2:

from time import time as t def count(): st = t() [x for x in xrange(10000000) if x%4 == 0] et = t() print et-st count() 

2) Python3:

 from time import time as t def xrange(x): return iter(range(x)) def count(): st = t() [x for x in xrange(10000000) if x%4 == 0] et = t() print (et-st) count() 

结果分别是:

1) 1.53888392448 2) 3.215819835662842

这是为什么? 我的意思是,为什么xrange被删除? 这是一个很好的学习工具。 对于初学者来说,就像我们一样,我们都在某个时刻。 为什么要删除它? 有人可以指我适当的PEP,我找不到它。

干杯。

一些性能测量,使用时间,而不是试图手动与time

一,苹果2.7.2 64位:

 In [37]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0) 1 loops, best of 3: 1.05 s per loop 

现在,python.org 3.3.0 64位:

 In [83]: %timeit collections.deque((x for x in range(10000000) if x%4 == 0), maxlen=0) 1 loops, best of 3: 1.32 s per loop In [84]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0) 1 loops, best of 3: 1.31 s per loop In [85]: %timeit collections.deque((x for x in iter(range(10000000)) if x%4 == 0), maxlen=0) 1 loops, best of 3: 1.33 s per loop 

显然,3.x range确实比2.x xrange慢了一点。 OP的xrange函数与它无关。 (毫不奇怪,对于__iter__插槽的一次调用在10000000次调用中不太可能看到循环中发生的任何事情,但有人提出了这种可能性。)

但速度只有30%。 OP如何慢得两倍? 那么,如果我用32位的Python重复相同的testing,我得到1.58比3.12。 所以我的猜测是,这是另一种情况下,3.x已被优化的64位性能的方式伤害32位。

但这真的很重要吗? 检查一下,再次用3.3.0 64位:

 In [86]: %timeit [x for x in range(10000000) if x%4 == 0] 1 loops, best of 3: 3.65 s per loop 

所以,构buildlist时间比整个迭代长两倍多。

至于“比Python 2.6+消耗更多的资源”,从我的testing看来,它看起来像一个3.x range是一个大小和2.x xrange完全一样 – 即使它是10倍大,构build不必要的列表仍然是大约1000万倍以上的问题,而不是范围迭代可能做的任何事情。

那么明确的for循环,而不是在deque里面的C循环呢?

 In [87]: def consume(x): ....: for i in x: ....: pass In [88]: %timeit consume(x for x in range(10000000) if x%4 == 0) 1 loops, best of 3: 1.85 s per loop 

所以,在for语句和在迭代range的实际工作中浪费的时间差不多。

如果你担心优化范围对象的迭代,那么你可能看错了地方。


同时,你不断地问为什么xrange被删除了,无论有多less人告诉你同样的事情,但我会再次重复一遍:它没有被删除:它被改名为range ,2.x range是什么除去。

这里有一些certificate3.3 range对象是2.x xrange对象(而不是2.x range函数)的直接后裔:源到3.3 range和2.7 xrange 。 你甚至可以看到更改历史logging (链接到,我相信,取代文件中任何位置的string“xrange”的最后一个实例的变化)。

那么为什么它变慢呢?

那么,他们已经增加了很多新function。 另一方面,他们做了各种各样的变化(特别是在迭代中),副作用很小。 而且还有很多工作要大大优化各种重要的案例,即使有时候稍微不重要的案件也会稍微悲观一些。 把这一切加起来,我并不感到惊讶的是,尽可能快地迭代一个range现在有点慢。 这是一个没有人关注的不太重要的案例之一。 没有人可能会有一个真实的使用案例,这种性能差异是他们代码中的热点。

Python3的范围 Python2的xrange。 没有必要在它周围包裹它。 要获得Python3中的实际列表,您需要使用list(range(...))

如果你想要一些适用于Python2和Python3的东西,试试这个

 try: xrange except NameError: xrange = range 

Python 3的rangetypes就像Python 2的xrange 。 我不知道为什么你会看到一个放缓,因为你的xrange函数返回的迭代器正是你所得到的,如果你直接迭代超过range

我无法在系统上重现速度变慢的情况。 以下是我testing的方法:

Python 2,与xrange

 Python 2.7.3 (default, Apr 10 2012, 23:24:47) [MSC v.1500 64 bit (AMD64)] on win32 Type "copyright", "credits" or "license()" for more information. >>> import timeit >>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100) 18.631936646865853 

Python 3中, range更快一点:

 Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64 bit (AMD64)] on win32 Type "copyright", "credits" or "license()" for more information. >>> import timeit >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100) 17.31399508687869 

我最近了解到,Python 3的rangetypes还有其他一些range(10,100,2)[5:25:5]特性,例如支持切片: range(10,100,2)[5:25:5]range(15, 60, 10) range(10,100,2)[5:25:5] range(15, 60, 10)

修正你的python2代码的一种方法是:

 import sys if sys.version_info >= (3, 0): def xrange(*args, **kwargs): return iter(range(*args, **kwargs)) 

comp:〜$ python Python 2.7.6(默认,2015年6月22日,17:58:13)[GCC 4.8.2] on linux2

 >>> import timeit >>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100) 

5.656799077987671

 >>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100) 

5.579368829727173

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100) 

21.54827117919922

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100) 

22.014557123184204

随着时间编号= 1参数:

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1) 

0.2245171070098877

 >>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=1) 

0.10750913619995117

comp:〜$ python3 Python 3.4.3(默认,2015年10月14日,20:28:29)[GCC 4.8.4] on linux

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100) 

9.113872020003328

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100) 

9.07014398300089

随着timeit号码= 1,2,3,4参数快速和线性的方式工作:

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1) 

0.09329321900440846

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=2) 

0.18501482300052885

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=3) 

0.2703447980020428

 >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=4) 

0.36209142999723554

所以看起来如果我们测量一个像timeit.timeit(“[x for x in range(1000000)if x%4]”,number = 1)(如我们在实际代码中所使用的)运行循环周期似乎python3工作足够快,但在重复循环python2 xrange()赢得速度对python3范围()。