TL; DR - NUMERO 21118
La lunga storia
Josh Rosenberg ha scoperto che la str.translate()
funzione è molto lenta rispetto a bytes.translate
, ha sollevato un problema , affermando che:
In Python 3, di str.translate()
solito è una pessimizzazione delle prestazioni, non un'ottimizzazione.
Perché era str.translate()
lento?
La ragione principale per str.translate()
essere molto lenti era che la ricerca era in un dizionario Python.
L'uso di maketrans
ha peggiorato questo problema. L'approccio simile che utilizza bytes
crea un array C di 256 elementi per una rapida ricerca nella tabella. Quindi l'uso di Python di livello superiore dict
rende str.translate()
molto lento in Python 3.4.
Cos'è successo ora?
Il primo approccio è stato quello di aggiungere una piccola patch, translate_writer , tuttavia l'aumento di velocità non è stato così piacevole. Presto è stata testata un'altra patch fast_translate che ha prodotto ottimi risultati con un aumento di velocità fino al 55%.
Il cambiamento principale, come si può vedere dal file, è che la ricerca nel dizionario Python viene modificata in una ricerca di livello C.
Le velocità ora sono quasi le stesse di bytes
unpatched patched
str.translate 4.55125927699919 0.7898181750006188
str.translate from bytes trans 1.8910855210015143 0.779950579000797
Una piccola nota qui è che il miglioramento delle prestazioni è prominente solo nelle stringhe ASCII.
Come menzionato da JFSebastian in un commento sotto, prima della 3.5, la traduzione funzionava allo stesso modo sia per i casi ASCII che per quelli non ASCII. Tuttavia da 3.5 ASCII case è molto più veloce.
Precedenti ASCII vs non ASCII erano quasi gli stessi, tuttavia ora possiamo vedere un grande cambiamento nelle prestazioni.
Può essere un miglioramento da 71,6μs a 2,33μs come si vede in questa risposta .
Il codice seguente lo dimostra
python3.5 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
100000 loops, best of 3: 2.3 usec per loop
python3.5 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
10000 loops, best of 3: 117 usec per loop
python3 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
10000 loops, best of 3: 91.2 usec per loop
python3 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
10000 loops, best of 3: 101 usec per loop
Tabulazione dei risultati:
Python 3.4 Python 3.5
Ascii 91.2 2.3
Unicode 101 117
dict.fromkeys(ord(c) for c in '@#$')
?