[英]Why is there no xrange function in Python3?
最近,我開始使用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,我找不到它。
干杯。
使用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
函數與此無關。 (不足為奇,因為一次調用__iter__
插槽不太可能在循環中發生的1000萬次調用中看到,但有人提出來了。)
但這僅慢了30%。 OP如何使速度慢2倍? 好吧,如果我對32位Python重復相同的測試,則得出的結果是1.58和3.12。 因此,我的猜測是,這是3.x針對64位性能進行了優化(以損害32位的方式)的又一案例。
但這真的重要嗎? 再次使用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
花費的時間是整個迭代過程的兩倍以上。
至於“比Python 2.6+消耗更多的資源”,在我的測試中,看起來3.x range
的大小與2.x xrange
大小完全相同,即使它的大小是10倍,也可以構建不必要的列表仍然比范圍迭代可能做的任何事情多出大約10000000x的問題。
那么在deque
使用顯式的for
循環而不是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 range
和2.7 xrange
的源。 您甚至可以查看更改歷史記錄 (我相信,該更改鏈接到替換了文件中任何位置的字符串“ xrange”的最后一個實例)。
那么,為什么它變慢?
好吧,其中之一是,他們添加了許多新功能。 另一方面,他們已經在整個地方(尤其是在迭代過程中)進行了各種具有較小副作用的更改。 盡管有時有時會稍微低估不太重要的案例,但仍進行了大量工作來顯着優化各種重要案例。 把所有這些加起來,讓我感到驚訝的是,盡可能快地迭代range
現在變慢了。 這是最重要的案例之一,沒有人會足夠關注。 沒有人會遇到現實中的用例,這種性能差異是他們代碼中的熱點。
Python3的范圍是 Python2的xrange。 無需在其周圍包裝迭代器。 要在Python3中獲取實際列表,您需要使用list(range(...))
如果您想要適用於Python2和Python3的產品,請嘗試以下操作
try:
xrange
except NameError:
xrange = range
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
具有range
Python 3快一點:
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(20, 60, 10)
range(10,100,2)[5:25:5]
range(20, 60, 10)
!
修復python2代碼的一種方法是:
import sys
if sys.version_info >= (3, 0):
def xrange(*args, **kwargs):
return iter(range(*args, **kwargs))
Python 2中的xrange是一個生成器並實現迭代器,而range只是一個函數。 在Python3中,我不知道為什么從xrange中刪除。
comp:〜$ python Python 2.7.6(default,Jun 22 2015,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
>>> 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
當timeit number = 1參數時:
>>> 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
如果timeit number = 1,2,3,4,則參數可以快速線性地工作:
>>> 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表示x在range(1000000)中,如果x%4]”,number = 1)(正如我們在實際代碼中實際使用的那樣),python3的運行速度足夠快,但在重復循環中,python 2 xrange()在速度上勝過python 3中的range()。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.