Alcune misurazioni delle prestazioni, usando timeitinvece di provare a farlo manualmente con time.
Innanzitutto, Apple 2.7.2 a 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
Ora, python.org 3.3.0 a 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
A quanto pare, 3.x rangeè davvero un po 'più lento di 2.x xrange. E la xrangefunzione del PO non ha nulla a che fare con esso. (Non sorprende, dal momento che una chiamata una tantum allo __iter__slot non è probabilmente visibile tra 10000000 chiamate a qualsiasi cosa accada nel loop, ma qualcuno lo ha sollevato come una possibilità.)
Ma è solo il 30% più lento. In che modo l'OP ha ottenuto 2x più lento? Bene, se ripeto gli stessi test con Python a 32 bit, ottengo 1,58 contro 3,12. Quindi la mia ipotesi è che questo è ancora un altro di quei casi in cui 3.x è stato ottimizzato per le prestazioni a 64 bit in modo da danneggiare 32-bit.
Ma importa davvero? Dai un'occhiata, con 3.3.0 di nuovo a 64 bit:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
Quindi, la costruzione di listrichiede più del doppio dell'intera iterazione.
E per quanto riguarda "consuma molte più risorse di Python 2.6+", dai miei test, sembra che una 3.x rangeabbia esattamente le stesse dimensioni di una 2.x xrange- e, anche se fosse 10x più grande, costruendo l'elenco non necessario è ancora circa 10000000 volte più un problema di qualsiasi altra cosa possa fare l'iterazione dell'intervallo.
E che dire di un forciclo esplicito anziché del ciclo C all'interno 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
Quindi, quasi tutto il tempo perso fornell'affermazione come nel lavoro effettivo di iterazione di range.
Se sei preoccupato di ottimizzare l'iterazione di un oggetto range, probabilmente stai cercando nel posto sbagliato.
Nel frattempo, continui a chiederti perché è xrangestato rimosso, non importa quante volte le persone ti dicono la stessa cosa, ma lo ripeterò di nuovo: non è stato rimosso: è stato rinominato rangee la 2.x rangeè ciò che è stato rimosso.
Ecco alcune prove del fatto che l' rangeoggetto 3.3 è un discendente diretto xrangedell'oggetto 2.x (e non della rangefunzione 2.x ): l'origine a 3.3range e 2.7xrange . Puoi persino vedere la cronologia delle modifiche (collegata, credo, alla modifica che ha sostituito l'ultima istanza della stringa "xrange" in qualsiasi punto del file).
Quindi, perché è più lento?
Bene, per uno, hanno aggiunto molte nuove funzionalità. Per un altro, hanno fatto tutti i tipi di cambiamenti in tutto il luogo (specialmente all'interno dell'iterazione) che hanno effetti collaterali minori. E c'era stato un sacco di lavoro per ottimizzare drasticamente vari casi importanti, anche se a volte pessimizza leggermente i casi meno importanti. Aggiungilo tutto e non mi sorprende che iterare il rangepiù velocemente possibile sia ora un po 'più lento. È uno di quei casi meno importanti su cui nessuno si preoccuperebbe mai abbastanza di concentrarsi. Nessuno probabilmente avrà mai un caso d'uso reale in cui questa differenza di prestazioni è l'hotspot nel proprio codice.
rangein Python 3.xxrangeproviene da Python 2.x. Fu infattirangerimosso Python 2.x.