首页 文章

为什么Python3中没有xrange函数?

提问于
浏览
225

最近我开始使用Python3,它缺乏xrange的伤害 .

简单的例子:

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

这是为什么?我的意思是,为什么xrange被删除了?这是一个很好的学习工具 . 对于初学者来说,就像我一样,就像我们所有人一样 . 为什么删除它?有人能指出我正确的PEP,我找不到它 .

干杯 .

6 回答

  • 13

    修复python2代码的一种方法是:

    import sys
    
    if sys.version_info >= (3, 0):
        def xrange(*args, **kwargs):
            return iter(range(*args, **kwargs))
    
  • 124

    一些性能测量,使用 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.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 loops, best of 3: 3.65 s per loop
    

    因此,构建 list 的时间比整个迭代长两倍多 .

    至于"consumes much more resources than Python 2.6+",从我的测试来看,它看起来像3.x range 与2.x xrange 完全相同 - 即使它是10倍大,构建不必要的列表仍然是大约10000000倍问题比范围迭代可能做的任何事情都要多 .

    那个显式的 for 循环而不是 deque 中的C循环呢?

    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 被删除,无论人们多少次告诉你同样的事情,但我会再次重复:它没有删除:它被重命名为 range ,而2.x range 是什么的除去 .

    这里有一些证据证明3.3 range 对象是2.x xrange 对象的直接后代(而不是2.x range 函数):3.3 range2.7 xrange的源 . 您甚至可以看到change history(链接到,我相信,更改了替换文件中任何位置的字符串"xrange"的最后一个实例) .

    那么,为什么它会变慢?

    嗯,对于其中一个,他们已经做了各种各样的变化(特别是在迭代中),这些变化有轻微的副作用 . 并且'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'毫不奇怪,尽可能快地迭代 range 现在有点慢 . 这是一个不那么重要的案例,没有人会关注到足够关注 . 任何人都不可能有一个真实的用例,其中这种性能差异是他们代码中的热点 .

  • 1

    Python 3的 range 类型就像Python 2的 xrange 一样 . 我看到了一个减速,因为 xrange 函数返回的迭代器正是你直接迭代 range 所得到的 .

    我无法重现系统的减速 . 这是我测试的方式:

    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, 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
    

    我最近了解到Python 3的 range 类型还有一些其他简洁的功能,比如支持切片: range(10,100,2)[5:25:5]range(15, 60, 10)

  • 0

    comp:~$ python Python 2.7.6(默认,2015年6月22日,17:58:13)linux2上的[GCC 4.8.2]

    >>> import timeit
    >>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)
    

    5.656799077987671

    >>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=100)
    

    5.579368829727173

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
    

    21.54827117919922

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
    

    22.014557123184204

    With timeit number=1 param:

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1)
    

    0.2245171070098877

    >>> timeit.timeit("[x for x in xrange(1000000) if x%4]",number=1)
    

    0.10750913619995117

    comp:~$ python3 Python 3.4.3(默认,2015年10月14日,20:28:29)[GCC 4.8.4]在linux上

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
    

    9.113872020003328

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=100)
    

    9.07014398300089

    With timeit number=1,2,3,4 param works quick and in linear way:

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=1)
    

    0.09329321900440846

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=2)
    

    0.18501482300052885

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=3)
    

    0.2703447980020428

    >>> timeit.timeit("[x for x in range(1000000) if x%4]",number=4)
    

    0.36209142999723554

    因此,如果我们测量1个正在运行的循环周期,例如timeit.timeit(“[x for x in range(1000000)if x%4]”,number = 1)(正如我们在实际代码中实际使用的那样),python3工作得足够快,但是在重复循环中,python 2 xrange()在python 3中对range()的速度获胜 .

  • -2

    Python3的范围是Python2 's xrange. There',无需围绕它进行包装 . 要在Python3中获取实际列表,您需要使用 list(range(...))

    如果你想要一些适用于Python2和Python3的东西,试试这个

    try:
        xrange
    except NameError:
        xrange = range
    
  • 146

    Python 2中的xrange是一个生成器并实现了迭代器,而range只是一个函数 . 在Python3中,我不知道为什么从xrange中删除了 .

相关问题