Niektóre pomiary wydajności, używając timeitzamiast próbować to zrobić ręcznie time.
Po pierwsze, 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
Teraz 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
Najwyraźniej 3.x rangenaprawdę jest nieco wolniejszy niż 2.x xrange. A funkcja PO nie xrangema 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:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
Tak więc budowanie listzajmuje 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 rangema dokładnie taki sam rozmiar jak 2.x xrange- 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ą forpętlą zamiast pętli C w środku 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
Tak więc prawie tyle samo czasu zmarnowano na foroś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 xrangezostał 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 na range, a 2.x rangejest tym, co zostało usunięte.
Oto kilka dowodów na to, że rangeobiekt 3.3 jest bezpośrednim potomkiem xrangeobiektu 2.x (a nie rangefunkcji 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 rangetak 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.
rangew Python 3.x pochodzixrangez Python 2.x. W rzeczywistościrangeusunięto Python 2.x.