为什么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的range
types就像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的range
types还有其他一些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范围()。