为什么Python3中没有xrange函数?

cat*_*sia 259 python xrange pep python-3.x

最近我开始使用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()
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

结果分别是:

1) 1.53888392448 2) 3.215819835662842

这是为什么?我的意思是,为什么xrange被删除了?这是一个很好的学习工具.对于初学者,就像我一样,就像我们所有人一样.为什么删除它?有人能指出我正确的PEP,我找不到它.

干杯.

aba*_*ert 168

一些性能测量,timeit而不是尝试手动执行time.

首先,Apple 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
Run Code Online (Sandbox Code Playgroud)

现在,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
Run Code Online (Sandbox Code Playgroud)

显然,3.x range确实比2.x慢一点xrange.OP的xrange功能与它无关.(这并不奇怪,因为__iter__在循环中发生的10000000 次调用中,对插槽的一次性调用不太可见,但是有人提出这种情况是可能的.)

但它只慢了30%.OP如何获得2倍的速度?好吧,如果我用32位Python重复相同的测试,我得到1.58和3.12.所以我的猜测是,这是另一种情况,其中3.x已经针对32位的方式针对64位性能进行了优化.

但它真的重要吗?再次检查这一点,再次使用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
Run Code Online (Sandbox Code Playgroud)

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

至于"消耗比Python 2.6+更多的资源",从我的测试来看,它看起来像3.x range与2.x的大小完全相同xrange- 即使它是10倍大,也构建了不必要的列表仍然比范围迭代可能做的任何问题多出约10000000倍.

那么显式for循环而不是内部的C循环deque呢?

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
Run Code Online (Sandbox Code Playgroud)

因此,在for声明中浪费的时间几乎和迭代的实际工作一样多range.

如果您担心优化范围对象的迭代,那么您可能正在查找错误的位置.


与此同时,你不断问为什么xrange被删除,无论人们多少次告诉你同样的事情,但我会再次重复:它没有被删除:它被重命名为range,2.x range就是删除了.

这里有一些证明3.3 range对象是2.x xrange对象的直接后代(而不是2.x range函数):3.3range2.7xrange的源.您甚至可以看到更改历史记录(我相信,链接到文件中任何位置替换字符串"xrange"的最后一个实例的更改).

那么,为什么它会变慢?

嗯,首先,他们添加了许多新功能.另一方面,他们在整个地方(特别是在迭代内部)做了各种各样的改变,这些改变都有轻微的副作用.并且已经做了很多工作来大幅优化各种重要案例,即使它有时会使不太重要的案例略微悲观.加上这一切,我并不感到惊讶,range尽可能快地迭代现在有点慢.这是一个不那么重要的案例,没有人会关注到足够关注.任何人都不可能有一个真实的用例,其中这种性能差异是他们代码中的热点.

  • @catalesia:是的,确切地说.但你似乎认为这与它所说的相反.这不是任何人都会关心的用例,所以没有人注意到它的速度慢了30%.所以呢?如果你能找到一个在Python 3.3中比在2.7(或2.6)中运行得更慢的真实程序,那么人们会关心.如果你不能,他们就不会,你也不应该. (17认同)
  • @catalesia:再次,它没有删除,它只是重命名为`range`.3.3中的`range`对象是2.7中`xrange`对象的直接后代,而不是2.7中``range`函数的直接后代.这就像在问题`itertools.imap`被删除而转而选择`map`时.没有答案,因为没有发生这样的事情. (8认同)

Joh*_*ooy 137

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

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

try:
    xrange
except NameError:
    xrange = range
Run Code Online (Sandbox Code Playgroud)

  • 问题在于,使用`range`和`xrange`的代码将表现不同.这样做是不够的,还必须确保永远不要假设`range`返回一个列表(就像在python 2中那样). (3认同)
  • 有时您需要同时在 Python 2 和 3 中运行的代码。这是一个很好的解决方案。 (2认同)

Blc*_*ght 16

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

我最近了解到Python 3的range类型还有其他一些简洁的功能,比如支持切片:range(10,100,2)[5:25:5]range(20, 60, 10)!

  • @catalesia我认为这里的重点是`xrange`被_not_删除,只是_renamed_. (3认同)
  • 就我而言,3.x"范围"中最大的胜利是恒定时间`__contains__`.新手曾经写过`300000 in xrange(1000000)`并导致它迭代整个`xrange`(或至少前30%),所以我们必须解释为什么这是一个坏主意,即使它看起来如此pythonic.现在,它_is_ pythonic. (3认同)