Ostatnio zacząłem używać Python3 i brak jest xrange boli.
Prosty przykład:
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()
Wyniki to odpowiednio:
1) 1,53888392448 2) 3,215819835662842
Dlaczego? To znaczy, dlaczego xrange został usunięty? To takie świetne narzędzie do nauki. Dla początkujących, tak jak ja, jakbyśmy wszyscy byli w pewnym momencie. Po co to usuwać? Czy ktoś może wskazać mi właściwy PEP, nie mogę go znaleźć.
Twoje zdrowie.
python
python-3.x
pep
xrange
catalesia
źródło
źródło
range
w Python 3.x pochodzixrange
z Python 2.x. W rzeczywistościrange
usunięto Python 2.x.time
. Poza tym, że jest łatwiejszy w użyciu i trudniejszy do popełnienia błędu, a powtarzanie testów za Ciebie,timeit
zajmuje się wszystkimi rzeczami, których nie pamiętasz, a nawet nie wiesz, jak się nimi zająć (np. Wyłączenie GC), i możesz użyć zegar z tysiąc razy lepszą rozdzielczością.range
nax%4 == 0
? Dlaczego nie po prostu przetestowaćlist(xrange())
kontralist(range())
, więc jest jak najmniej zbędnej pracy? (Na przykład, skąd wiesz, że 3.x nie działax%4
wolniej?) W takim razie, dlaczego budujesz ogromnąlist
, która wymaga całej alokacji pamięci (która oprócz tego, że jest powolna, jest również niesamowicie zmienna) ?iter(range)
jest zbędny.list(range(..))
. Jest to równoważne zasięgowi Pythona 2. Lub mówiąc inaczej: xrange został przemianowany na range, ponieważ jest to lepszy domyślny; nie trzeba było mieć obu,list(range)
jeśli naprawdę potrzebujesz listy. .Odpowiedzi:
Niektóre pomiary wydajności, używając
timeit
zamiast próbować to zrobić ręcznietime
.Po pierwsze, Apple 2.7.2 64-bit:
Teraz python.org 3.3.0 64-bit:
Najwyraźniej 3.x
range
naprawdę jest nieco wolniejszy niż 2.xxrange
. A funkcja PO niexrange
ma z tym nic wspólnego. (Nic dziwnego, ponieważ jednorazowe połączenie do__iter__
automatu prawdopodobnie nie będzie widoczne wśród 10000000 połączeń z tym, co dzieje się w pętli, ale ktoś przywołał to jako możliwość).Ale to tylko 30% wolniej. W jaki sposób PO stał się 2x tak wolny? Cóż, jeśli powtórzę te same testy z 32-bitowym Pythonem, otrzymam 1,58 vs. 3,12. Domyślam się, że jest to kolejny przypadek, w którym 3.x został zoptymalizowany pod kątem wydajności 64-bitowej w sposób, który szkodzi 32-bitowej.
Ale czy to naprawdę ma znaczenie? Sprawdź to ponownie w wersji 64.0 64-bitowej:
Tak więc budowanie
list
zajmuje więcej niż dwa razy więcej niż cała iteracja.A jeśli chodzi o „zużywa znacznie więcej zasobów niż Python 2.6+”, z moich testów wygląda na to, że 3.x
range
ma dokładnie taki sam rozmiar jak 2.xxrange
- i nawet jeśli byłby 10 razy większy , budowanie niepotrzebnej listy wciąż stanowi około 10000000 razy większy problem niż cokolwiek, co mogłaby zrobić iteracja zakresu.A co z wyraźną
for
pętlą zamiast pętli C w środkudeque
?Tak więc prawie tyle samo czasu zmarnowano na
for
oświadczenie, jak na faktyczną pracę nad iteracjąrange
.Jeśli martwisz się optymalizacją iteracji obiektu zakresu, prawdopodobnie patrzysz w niewłaściwe miejsce.
W międzyczasie wciąż pytasz, dlaczego
xrange
został usunięty, bez względu na to, ile razy ludzie mówią ci to samo, ale powtórzę to jeszcze raz: nie został usunięty: został przemianowany narange
, a 2.xrange
jest tym, co zostało usunięte.Oto kilka dowodów na to, że
range
obiekt 3.3 jest bezpośrednim potomkiemxrange
obiektu 2.x (a nierange
funkcji 2.x ): źródło do 3.3range
i 2.7xrange
. Możesz nawet zobaczyć historię zmian (powiązaną, jak sądzę, ze zmianą, która zastąpiła ostatnie wystąpienie ciągu „xrange” w dowolnym miejscu pliku).Dlaczego więc jest wolniejszy?
Po pierwsze, dodali wiele nowych funkcji. Po drugie, wprowadzili wszelkiego rodzaju zmiany w całym miejscu (szczególnie w iteracji), które mają niewielkie skutki uboczne. Dużo pracy włożono w radykalną optymalizację różnych ważnych przypadków, nawet jeśli czasami nieznacznie pesymalizuje mniej ważne przypadki. Dodaj to wszystko i nie dziwię się, że iterowanie
range
tak szybko, jak to możliwe, jest teraz nieco wolniejsze. Jest to jeden z tych mniej ważnych przypadków, na których nikt nigdy by się nie przejmował, na czym mógł się skupić. Nikt nigdy nie będzie miał rzeczywistego przypadku użycia, w którym ta różnica wydajności jest hotspotem w kodzie.źródło
range
.range
Obiekt w 3.3 bezpośredniego potomka tegoxrange
przedmiotu w 2,7, a nie wrange
zależności na 2,7. To tak, jakby pytać, kiedyitertools.imap
został usunięty na korzyśćmap
. Nie ma odpowiedzi, ponieważ nic takiego się nie wydarzyło.range
, nie robiąc nic więcej.Zakres Python3 to xrange Python2. Nie ma potrzeby owijania go iterem. Aby uzyskać rzeczywistą listę w Python3, musisz użyć
list(range(...))
Jeśli chcesz czegoś, co działa z Python2 i Python3, spróbuj tego
źródło
range
ixrange
zachowuje się inaczej. Nie wystarczy to zrobić, trzeba też upewnić się, że nigdy nie zakłada się, żerange
zwraca listę (tak jak w Pythonie 2).futurize
narzędzie do automatycznej konwersji kodu źródłowego: python-future.org/…range
Typ Python 3 działa tak samo jak Python 2xrange
. Nie jestem pewien, dlaczego obserwujesz spowolnienie, ponieważ iterator zwrócony przez twojąxrange
funkcję jest dokładnie tym, co byś otrzymał, gdybyś iterowałrange
bezpośrednio.Nie jestem w stanie odtworzyć spowolnienia w moim systemie. Oto jak testowałem:
Python 2 z
xrange
:Python 3, z
range
jest trochę szybszy:Niedawno dowiedziałem się, że
range
typ Pythona 3 ma kilka innych fajnych funkcji, takich jak obsługa krojenia:range(10,100,2)[5:25:5]
isrange(20, 60, 10)
!źródło
xrange
tak wiele razy, czy może to zrobić tylko raz?xrange
został usunięty, tylko zmieniono jego nazwę .range
jest czas stały__contains__
. Początkujący pisali,300000 in xrange(1000000)
co powodowało iterację całościxrange
(lub przynajmniej pierwszych 30%), więc musieliśmy wyjaśnić, dlaczego był to zły pomysł, nawet jeśli wygląda tak pytonicznie. Teraz jest pytoniczny.Jednym ze sposobów naprawienia kodu python2 jest:
źródło
range = xrange
jak skomentował @John La Royxrange = range
... zamieniłem instrukcjexrange z Python 2 jest generatorem i implementuje iterator, podczas gdy zasięg jest tylko funkcją. W Python3 nie wiem, dlaczego porzucono Xrange.
źródło
range()
jest odpowiednikiem PY2xrange()
. I tak w PY3xrange()
jest zbędny.comp: ~ $ python Python 2.7.6 (domyślnie, 22 czerwca 2015, 17:58:13) [GCC 4.8.2] na linux2
5.656799077987671
5.579368829727173
21.54827117919922
22.014557123184204
Z numerem czasu = 1 parametr:
0,2245171070098877
0,10750913619995117
comp: ~ $ python3 Python 3.4.3 (domyślnie, 14 października 2015, 20:28:29) [GCC 4.8.4] w systemie Linux
9.113872020003328
9,07014398300089
Z liczbą timeit = 1,2,3,4 param działa szybko i liniowo:
0,09329321900440846
0,18501482300052885
0,2703447980020428
0,36209142999723554
Wydaje się więc, że jeśli zmierzymy 1 działający cykl pętli, taki jak timeit.timeit („[x dla xw zakresie (1000000), jeśli x% 4]”, liczba = 1) (tak jak w rzeczywistości używamy w prawdziwym kodzie) python3 działa wystarczająco szybko, ale w powtarzających się pętlach python 2 xrange () wygrywa z prędkością w stosunku do range () z python 3.
źródło