为什么 Python3 中没有 xrange 函数? [英] Why is there no xrange function in Python3?
问题描述
最近我开始使用 Python3,它缺少 xrange
很痛苦.
简单例子:
Python2:
from time 导入时间为 t定义计数():st = t()[x for x in xrange(10000000) if x%4 == 0]et = t()印刷等数数()
Python3:
from time 导入时间为 tdef xrange(x):返回迭代器(范围(x))定义计数():st = t()[x for x in xrange(10000000) if x%4 == 0]et = t()打印 (et-st)数数()
结果分别为:
1.53888392448
3.215819835662842
这是为什么?我的意思是,为什么 xrange
已被删除?这是一个非常棒的学习工具.对于初学者来说,就像我一样,就像我们都在某个时候一样.为什么要删除它?有人可以给我指出正确的 PEP,我找不到.
一些性能测量,使用 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 个循环,最好的 3 个:每个循环 1.05 秒
现在,python.org 3.3.0 64 位:
In [83]: %timeit collections.deque((x for x in range(10000000) if x%4 == 0), maxlen=0)1 个循环,最好的 3 个:每个循环 1.32 秒在 [84]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)1 个循环,最好的 3 个:每个循环 1.31 秒在 [85]: %timeit collections.deque((x for x in iter(range(10000000)) if x%4 == 0), maxlen=0)1 个循环,最好的 3 个:每个循环 1.33 秒
显然,3.x range
确实比 2.x xrange
慢一点.而 OP 的 xrange
函数与它无关.(这并不奇怪,因为在对循环中发生的任何事情的 10000000 次调用中,对 __iter__
槽的一次性调用不太可能可见,但有人提出了这种可能性.)>
但它只慢了 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 个循环,最好的 3 个:每个循环 3.65 秒
因此,构建list
花费的时间是整个迭代的两倍多.
至于比 Python 2.6+ 消耗更多的资源",从我的测试来看,看起来 3.x range
与 2.x xrange 的大小完全相同
——而且,即使它是原来的 10 倍,构建不必要的列表仍然是一个比范围迭代可能做的任何事情都要多 10000000 倍的问题.
那么显式的 for
循环而不是 deque
中的 C 循环怎么样?
在[87]中:def消耗(x):....:对于 x 中的 i:....: 经过在 [88] 中:%timeit 消耗(x for x in range(10000000) if x%4 == 0)1 个循环,最好的 3 个:每个循环 1.85 秒
因此,在 for
语句中浪费的时间几乎与在迭代 range
的实际工作中浪费的时间一样多.
如果您担心优化范围对象的迭代,那么您可能找错了地方.
<小时>与此同时,你一直在问为什么 xrange
被删除了,不管人们告诉你多少次同样的事情,但我会再说一遍:它没有被删除:它被重命名为 range
,而 2.x range
是被删除的.
这里有一些证据表明 3.3 range
对象是 2.x xrange
对象(而不是 2.x range
对象)的直接后代code> 函数):3.3 range
的来源 和 2.7 xrange
.你甚至可以看到更改历史(链接到,我相信,替换文件中任何位置的字符串xrange"的最后一个实例的更改).
那么,为什么它变慢了?
首先,他们添加了许多新功能.另一方面,他们已经在所有地方(尤其是在迭代内部)进行了各种具有轻微副作用的更改.并且已经做了很多工作来显着优化各种重要的案例,即使它有时会略微悲观不太重要的案例.把这一切加起来,我并不感到惊讶的是,尽可能快地迭代 range
现在有点慢.这是那些不太重要的案例之一,没有人会足够关注.没有人可能在现实生活中遇到过这种性能差异是他们代码中的热点的用例.
Recently I started using Python3 and it's lack of xrange
hurts.
Simple example:
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()
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.53888392448
3.215819835662842
Why is that? I mean, why xrange
has 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.
Some performance measurements, using timeit
instead of trying to do it manually with time
.
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
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
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.)
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.
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
So, building the list
takes more than twice as long than the entire iteration.
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.
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
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.
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.
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).
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 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屋!