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

简单的例子:

Python2: 从时间导入时间为t def count (): St = t() [x for x in xrange(10000000)如果x%4 == 0] Et = t() 打印et-st count () Python3: 从时间导入时间为t def xrange (x): 返回iter(范围(x)) def count (): St = t() [x for x in xrange(10000000)如果x%4 == 0] Et = t() 打印(et-st) count ()

结果分别为:

1.53888392448 3.215819835662842

为什么呢?我是说,为什么xrange被删除了?这是一个很好的学习工具。对于初学者来说,就像我一样,就像我们所有人一样。为什么要移除它?谁能告诉我正确的PEP,我找不到。


当前回答

修复python2代码的一种方法是:

import sys

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

其他回答

Python 2中的xrange是一个生成器并实现迭代器,而range只是一个函数。 在Python3中,我不知道为什么会从xrange中删除。

薪酬:~ $ python Python 2.7.6(默认,2015年6月22日,17:58:13) [GCC 4.8.2

>>> 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

timeit number=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

薪酬:~ python3美元 Python 3.4.3(默认,Oct 14 2015, 20:28:29) [GCC 4.8.4

>>> 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

因此,如果我们测量1个运行的循环周期,比如timeit。Timeit ("[x for x in range(1000000) if x%4]",number=1)(正如我们在实际代码中使用的那样)python3工作得足够快,但在重复循环中,python 2 xrange()在速度上胜过python3的range()。

Python3的range是Python2的xrange。没必要用iter来包裹它。要在Python3中获得一个实际的列表,需要使用list(range(…))

如果你想要在Python2和Python3中工作,试试这个

try:
    xrange
except NameError:
    xrange = range

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

首先,苹果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范围确实比2要慢一点。x xrange。OP的xrange函数与此无关。(这并不奇怪,因为对__iter__槽的一次性调用不太可能在对循环中发生的任何事情的10000000个调用中可见,但有人提出了这种可能性。)

但它只慢了30%。OP怎么慢了两倍?好吧,如果我用32位的Python重复同样的测试,我得到1.58 vs. 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

因此,构建列表所花费的时间是整个迭代的两倍多。

至于“比Python 2.6+消耗更多的资源”,从我的测试来看,它看起来像3。X范围与2的大小完全相同。xrange—并且,即使它是它的10倍大,构建不必要的列表仍然比range迭代可能做的任何事情都要麻烦大约1000000倍。

用显式的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被删除了,不管人们告诉你多少次同样的事情,但我再重复一遍:它没有被删除:它被重命名为range,而2。X范围是被移除的部分。

下面是3.3 range对象是2的直接后代的一些证明。xrange对象(而不是2。X范围功能):源到3.3范围和2.7 xrange。您甚至可以看到更改历史(我相信是链接到替换文件中字符串“xrange”的最后一个实例的更改)。

那么,为什么它变慢了呢?

Well, for one, they've added a lot of new features. For another, they've done all kinds of changes all over the place (especially inside iteration) that have minor side effects. And there'd been a lot of work to dramatically optimize various important cases, even if it sometimes slightly pessimizes less important cases. Add this all up, and I'm not surprised that iterating a range as fast as possible is now a bit slower. It's one of those less-important cases that nobody would ever care enough to focus on. No one is likely to ever have a real-life use case where this performance difference is the hotspot in their code.

修复python2代码的一种方法是:

import sys

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