为什么 Python3 中没有 xrange 函数? [英] Why is there no xrange function in Python3?

查看:28
本文介绍了为什么 Python3 中没有 xrange 函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我开始使用 Python3,它缺少 xrange 很痛苦.

简单例子:

  1. Python2:

     from time 导入时间为 t定义计数():st = t()[x for x in xrange(10000000) if x%4 == 0]et = t()印刷等数数()

  2. Python3:

     from time 导入时间为 tdef xrange(x):返回迭代器(范围(x))定义计数():st = t()[x for x in xrange(10000000) if x%4 == 0]et = t()打印 (et-st)数数()

结果分别为:

  1. 1.53888392448
  2. 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:

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

The results are, respectively:

  1. 1.53888392448
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆