为什么 Python3 中没有 xrange 函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15014310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is there no xrange function in Python3?
提问by catalesia
Recently I started using Python3 and it's lack of xrange hurts.
最近我开始使用 Python3,它缺少 xrange 很痛苦。
Simple example:
简单的例子:
1)Python2:
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:
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()
The results are, respectively:
结果分别为:
1)1.53888392448 2)3.215819835662842
1)1.53888392448 2)3.215819835662842
Why is that? I mean, why xrange's been removed? It's such a great tool to learn. For the beginners, just like myself, like we all were at some point. Why remove it? Can somebody point me to the proper PEP, I can't find it.
这是为什么?我的意思是,为什么 xrange 被删除了?这是一个很棒的学习工具。对于初学者来说,就像我一样,就像我们都在某个时候一样。为什么要删除它?有人可以指出我正确的 PEP,我找不到。
Cheers.
干杯。
采纳答案by abarnert
Some performance measurements, using timeitinstead of trying to do it manually with time.
一些性能测量,使用timeit而不是尝试使用time.
First, Apple 2.7.2 64-bit:
一、苹果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
Now, python.org 3.3.0 64-bit:
现在,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
Apparently, 3.x rangereally is a bit slower than 2.x xrange. And the OP's xrangefunction has nothing to do with it. (Not surprising, as a one-time call to the __iter__slot isn't likely to be visible among 10000000 calls to whatever happens in the loop, but someone brought it up as a possibility.)
显然, 3.xrange确实比 2.x 慢一点xrange。而OP的xrange功能与它无关。(这并不奇怪,因为__iter__在对循环中发生的任何事情的 10000000次调用中,对插槽的一次性调用不太可能可见,但有人提出了它的可能性。)
But it's only 30% slower. How did the OP get 2x as slow? Well, if I repeat the same tests with 32-bit Python, I get 1.58 vs. 3.12. So my guess is that this is yet another of those cases where 3.x has been optimized for 64-bit performance in ways that hurt 32-bit.
但它只慢了 30%。OP 是如何变慢 2 倍的?好吧,如果我用 32 位 Python 重复相同的测试,我会得到 1.58 与 3.12。所以我的猜测是,这是 3.x 以损害 32 位的方式针对 64 位性能进行了优化的另一种情况。
But does it really matter? Check this out, with 3.3.0 64-bit again:
但这真的重要吗?检查一下,再次使用 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
So, building the listtakes more than twice as long than the entire iteration.
因此,构建所需的list时间是整个迭代的两倍多。
And as for "consumes much more resources than Python 2.6+", from my tests, it looks like a 3.x rangeis exactly the same size as a 2.x xrange—and, even if it were 10x as big, building the unnecessary list is still about 10000000x more of a problem than anything the range iteration could possibly do.
至于“比 Python 2.6+ 消耗更多的资源”,从我的测试来看,3.x 看起来与range2.x 的大小完全相同xrange——而且,即使它是2.x 的10 倍,构建不必要的列表仍然是范围迭代可能做的任何事情的 10000000 倍以上的问题。
And what about an explicit forloop instead of the C loop inside deque?
那么显式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
So, almost as much time wasted in the forstatement as in the actual work of iterating the range.
因此,for语句中浪费的时间几乎与迭代range.
If you're worried about optimizing the iteration of a range object, you're probably looking in the wrong place.
如果您担心优化范围对象的迭代,那么您可能找错了地方。
Meanwhile, you keep asking why xrangewas removed, no matter how many times people tell you the same thing, but I'll repeat it again: It was not removed: it was renamed to range, and the 2.x rangeis what was removed.
同时,你一直在问为什么xrange被删除,不管人们告诉你多少次同样的事情,但我会再重复一遍:它没有被删除:它被重命名为range,而 2.xrange就是被删除的内容。
Here's some proof that the 3.3 rangeobject is a direct descendant of the 2.x xrangeobject (and not of the 2.x rangefunction): the source to 3.3 rangeand 2.7 xrange. You can even see the change history(linked to, I believe, the change that replaced the last instance of the string "xrange" anywhere in the file).
这里有一些证据表明 3.3range对象是 2.xxrange对象(而不是 2.xrange函数)的直接后代:3.3range和2.7xrange的源。您甚至可以看到更改历史记录(我相信链接到替换文件中任何位置的字符串“xrange”的最后一个实例的更改)。
So, why is it slower?
那么,为什么它会变慢?
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 rangeas 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.
嗯,一方面,他们添加了许多新功能。另一方面,他们已经在所有地方(尤其是在迭代内部)进行了各种具有轻微副作用的更改。并且已经做了很多工作来显着优化各种重要的案例,即使它有时会略微悲观不太重要的案例。把这一切加起来,我并不感到惊讶的是,range尽可能快地迭代 a现在有点慢。这是那些不太重要的案例之一,没有人会足够关注。没有人可能在现实生活中遇到这种性能差异是他们代码中的热点的用例。
回答by Blckknght
Python 3's rangetype works just like Python 2's xrange. I'm not sure why you're seeing a slowdown, since the iterator returned by your xrangefunction is exactly what you'd get if you iterated over rangedirectly.
Python 3 的range类型就像 Python 2 的xrange. 我不确定为什么你看到速度变慢,因为你的xrange函数返回的迭代器正是你range直接迭代得到的。
I'm not able to reproduce the slowdown on my system. Here's how I tested:
我无法在我的系统上重现减速。这是我测试的方法:
Python 2, with xrange:
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, with rangeis a tiny bit faster:
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
I recently learned that Python 3's rangetype has some other neat features, such as support for slicing: range(10,100,2)[5:25:5]is range(20, 60, 10)!
我最近了解到 Python 3 的range类型还有一些其他简洁的特性,比如支持切片:range(10,100,2)[5:25:5]is range(20, 60, 10)!
回答by John La Rooy
Python3's range isPython2's xrange. There's no need to wrap an iter around it. To get an actual list in Python3, you need to use list(range(...))
Python3 的范围是Python2 的 xrange。没有必要在它周围包裹一个迭代器。要在 Python3 中获取实际列表,您需要使用list(range(...))
If you want something that works with Python2 and Python3, try this
如果你想要一些适用于 Python2 和 Python3 的东西,试试这个
try:
xrange
except NameError:
xrange = range
回答by dmitriy
comp:~$ pythonPython 2.7.6 (default, Jun 22 2015, 17:58:13) [GCC 4.8.2] on linux2
comp:~$ pythonPython 2.7.6(默认,2015 年 6 月 22 日,17:58:13)[GCC 4.8.2] 在 linux2 上
>>> import timeit
>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)
5.656799077987671
5.656799077987671
>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)
5.579368829727173
5.579368829727173
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
21.54827117919922
21.54827117919922
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
22.014557123184204
22.014557123184204
With timeit number=1 param:
时间编号 = 1 参数:
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1)
0.2245171070098877
0.2245171070098877
>>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=1)
0.10750913619995117
0.10750913619995117
comp:~$ python3Python 3.4.3 (default, Oct 14 2015, 20:28:29) [GCC 4.8.4] on linux
comp:~$ python3Python 3.4.3(默认,2015 年 10 月 14 日,20:28:29)Linux 上的 [GCC 4.8.4]
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
9.113872020003328
9.113872020003328
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
9.07014398300089
9.07014398300089
With timeit number=1,2,3,4 param works quick and in linear way:
timeit number=1,2,3,4 参数以线性方式快速工作:
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1)
0.09329321900440846
0.09329321900440846
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=2)
0.18501482300052885
0.18501482300052885
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=3)
0.2703447980020428
0.2703447980020428
>>> timeit.timeit("[x for x in range(1000000) if x%4]",number=4)
0.36209142999723554
0.36209142999723554
So it seems if we measure 1 running loop cycle like timeit.timeit("[x for x in range(1000000) if x%4]",number=1) (as we actually use in real code) python3 works quick enough, but in repeated loops python 2 xrange() wins in speed against range() from python 3.
因此,如果我们测量 1 个运行循环周期,例如 timeit.timeit("[x for x in range(1000000) if x%4]",number=1) (正如我们在实际代码中实际使用的那样)python3 工作得足够快,但在重复循环中,python 2 xrange() 在速度上胜过 python 3 的 range()。
回答by andrew pate
One way to fix up your python2 code is:
修复 python2 代码的一种方法是:
import sys
if sys.version_info >= (3, 0):
def xrange(*args, **kwargs):
return iter(range(*args, **kwargs))
回答by Michel Fernandes
xrange from Python 2 is a generator and implements iterator while range is just a function. In Python3 I don't know why was dropped off the xrange.
Python 2 中的 xrange 是一个生成器并实现了迭代器,而 range 只是一个函数。在 Python3 中,我不知道为什么从 xrange 中删除。

