为什么Python3中没有xrange函数? [英] Why is there no xrange function in Python3?
问题描述
最近我开始使用Python3,它缺乏xrange的好处.
Recently I started using Python3 and it's lack of xrange hurts.
简单的例子:
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:
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
1) 1.53888392448 2) 3.215819835662842
那是为什么?我的意思是,为什么xrange被删除了?这是一个很棒的学习工具.对于初学者来说,就像我自己一样,就像我们所有人都处在某个时刻一样.为什么要删除它?有人可以指出我正确的PEP吗?
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.
干杯.
推荐答案
使用timeit
而不是尝试使用time
手动进行某些性能测量.
Some performance measurements, using timeit
instead of trying to do it manually with time
.
首先,Apple 2.7.2 64位:
First, Apple 2.7.2 64-bit:
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位:
Now, python.org 3.3.0 64-bit:
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__
插槽的一次调用不太可能在循环中发生的1000万次调用中看到,但有人提出来了).
Apparently, 3.x range
really is a bit slower than 2.x xrange
. And the OP's xrange
function 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.)
但是它只慢30%. OP如何获得2倍慢的速度?好吧,如果我对32位Python重复相同的测试,则得出的结果是1.58和3.12.因此,我的猜测是,这是3.x针对64位性能进行了优化(以损害32位的方式)的又一案例.
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.
但这真的很重要吗?再次使用64位3.3.0进行检查:
But does it really matter? Check this out, with 3.3.0 64-bit again:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
因此,构建list
所需的时间是整个迭代过程的两倍以上.
So, building the list
takes more than twice as long than the entire iteration.
在我的测试中,比Python 2.6+消耗的资源要多得多",看起来3.x range
的大小与2.x xrange
的大小完全相同,即使的大小是原来的10倍,那么构建不必要的列表仍然比范围迭代可能做的任何事情多出10000000倍.
And as for "consumes much more resources than Python 2.6+", from my tests, it looks like a 3.x range
is 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.
那用显式的for
循环而不是deque
内部的C循环呢?
And what about an explicit for
loop instead of the C loop inside 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
的实际工作中所浪费的时间一样.
So, almost as much time wasted in the for
statement as in the actual work of iterating the range
.
如果您担心优化范围对象的迭代,则可能在错误的位置.
If you're worried about optimizing the iteration of a range object, you're probably looking in the wrong place.
同时,您一直在问为什么删除xrange
,无论人们告诉您多少次相同的事情,但是我会再次重复:它没有被删除:它被重命名为range
,并且2.x range
是已删除的内容.
Meanwhile, you keep asking why xrange
was 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 range
is what was removed.
这里有一些证据表明3.3 range
对象是2.x xrange
对象(而不是2.x range
函数)的直接后代: 2.7 xrange
.您甚至可以看到更改历史记录(我相信链接到,该更改将替换文件中任何位置的字符串"xrange"的最后一个实例).
Here's some proof that the 3.3 range
object is a direct descendant of the 2.x xrange
object (and not of the 2.x range
function): the source to 3.3 range
and 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).
那么,为什么它变慢?
其中之一,他们添加了许多新功能.另一方面,他们已经在整个地方(尤其是在迭代过程中)进行了各种具有微小副作用的更改.尽管有时有时会稍微低估不太重要的案例,但仍进行了大量工作来显着优化各种重要案例.将所有这些加起来,对于尽快迭代range
现在会慢一点,我并不感到惊讶.这是最重要的案例之一,没有人会足够关注.没有人会遇到现实生活中的用例,这种性能差异是他们代码中的热点.
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.
这篇关于为什么Python3中没有xrange函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!