2015-09-08 15 views
10

La funzione join() accetta un parametro iterabile. Tuttavia, mi chiedevo perché avere:Python: comprensione degli iteratori e `join()` migliore

text = 'asdfqwer' 

questo:

''.join([c for c in text]) 

è significativamente più veloce:

''.join(c for c in text) 

Lo stesso si verifica con lunghe stringhe (vale a dire text * 10000000).

Guardando il footprint di memoria di entrambe le esecuzioni con stringhe lunghe, penso che entrambi creino una sola lista di caratteri in memoria, quindi li uniscano in una stringa. Quindi suppongo che la differenza sia solo tra il modo in cui join() crea questo elenco fuori dal generatore e in che modo l'interprete Python fa la stessa cosa quando vede [c for c in text]. Ma, di nuovo, sto solo supponendo, quindi vorrei che qualcuno confermasse/negassi le mie ipotesi.

+0

@AvinashRaj: dove vedi una tupla qui? – Matthias

+0

@Matthias ya, erroneamente menzionato come tupla al posto del generatore. –

+0

Probabilmente ti riferisci a: http://stackoverflow.com/a/9061024/3001761 – jonrsharpe

risposta

10

Il metodo join legge il suo ingresso due volte; una volta per determinare la quantità di memoria da allocare per l'oggetto stringa risultante, quindi di nuovo per eseguire il join effettivo. Passare una lista è più veloce che passare un oggetto generatore di cui ha bisogno per fare una copia in modo che possa iterare su di essa due volte.

Una comprensione di un elenco non è semplicemente un oggetto generatore racchiuso in un elenco, quindi la costruzione di un elenco esternamente è più veloce che avere join da un oggetto generatore. Gli oggetti del generatore sono ottimizzati per l'efficienza della memoria, non per la velocità.

Ovviamente, una stringa è già un oggetto iterabile, quindi è sufficiente scrivere ''.join(text). (Anche in questo caso non è così veloce come creare l'elenco esplicitamente dalla stringa.)

+0

Ho appena provato questo con un generatore che stampa. 'join' non ha eseguito il generatore due volte. È un reclamo abbastanza inverosimile. Cosa ti fa pensare che esegua il generatore due volte? –

+1

@DanielDarabos * "che ha bisogno di fare una copia di" * - consumandolo in una lista! – jonrsharpe

+2

Riproducendo il mio commento di domanda qui da quando lo hai menzionato nella tua risposta: È interessante notare che 'timeit' sul mio sistema mostra che una lista è più veloce dell'iterazione della stringa diretta anche qui. –

Problemi correlati