小能豆

为什么Python3中没有xrange函数?

py

最近我开始使用 Python3,它没有xrange什么缺点。

简单示例:

  1. Python2:

py 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()

  1. Python3:

```py
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 在哪里吗,我找不到。


阅读 50

收藏
2024-10-12

共1个答案

小能豆

一些性能测量,使用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

现在,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.xrange确实比 2.x 慢一点xrange。而 OP 的xrange功能与此无关。(这并不奇怪,因为__iter__在循环中发生的 10000000 次调用中,对插槽的一次性调用不太可能可见,但有人提出这是有可能的。)

但它只慢了 30%。楼主的速度怎么会慢 2 倍呢?好吧,如果我用 32 位 Python 重复同样的测试,我得到的结果为 1.58,而 3.12 则为 1.58。所以我猜这又是 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.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

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

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


同时,xrange无论别人多少次告诉你同样的事情,你还是会问为什么被删除,但我会再重复一遍:它并没有被删除:它被重命名为,并且被删除的是range2.x。range

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

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

嗯,首先,他们添加了很多新功能。其次,他们在各处(尤其是在迭代内部)做了各种各样的更改,这些更改的副作用很小。而且他们做了很多工作来显著优化各种重要情况,即使有时它稍微低估了不太重要的情况。把所有这些加起来,我并不惊讶尽可能range快的迭代现在变得有点慢了。这是那些不太重要的情况之一,没有人会足够关心并关注它。没有人可能在实际用例中遇到这种性能差异是他们代码中的热点。

2024-10-12