为什么Python3中没有xrange函数?

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

简单的例子:

  1. < p > 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. < p > 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,我找不到。

409544 次浏览

Python 3的range类型与Python 2的xrange类型工作方式相同。我不确定为什么你会看到速度减慢,因为你的xrange函数返回的迭代器正是你直接迭代range所得到的。

我无法在我的系统上重现减速。以下是我的测试方法:

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

使用range的Python 3稍微快一点:

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类型有一些其他漂亮的特性,比如支持切片:range(10,100,2)[5:25:5]range(20, 60, 10)!

一些性能测量,使用timeit而不是试图手动使用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重复同样的测试,我得到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

因此,构建list所需的时间是整个迭代的两倍多。

至于“比Python 2.6+消耗更多的资源”,从我的测试来看,它看起来像3。x range与2的大小完全相同。__abc1 -并且,即使它是它的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的实际工作中浪费的时间一样多。

如果您担心优化range对象的迭代,那么您可能找错地方了。


与此同时,你一直在问为什么xrange被删除了,不管人们告诉你多少次同样的事情,但我还是要重复一遍:它没有被删除:它被重命名为range,而2。x range是被删除的。

下面是3.3 range对象是2的直接后代的一些证明。xrange对象(而不是2. x xrange对象)。x range函数):源为3.3 range2.7 xrange。你甚至可以看到改变历史(我相信,链接到替换文件中字符串“xrange”的最后一个实例的更改)。

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

首先,他们增加了很多新功能。另一方面,他们在所有地方(尤其是在迭代中)做了各种各样的更改,这些更改有轻微的副作用。我们做了很多工作来极大地优化各种重要的情况,即使有时会使不那么重要的情况略显悲观。把这些都加起来,我并不惊讶,迭代range尽可能快现在有点慢。这是那些不太重要的案子之一,没有人会足够关心去关注。没有人可能在实际的用例中,这种性能差异是他们代码中的热点。

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

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

try:
xrange
except NameError:
xrange = range

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

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

< >强comp: ~ python3美元 Python 3.4.3(默认,Oct 14 2015, 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

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

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

import sys


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

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