TL; DR - ISSUE 21118
A longa história
Josh Rosenberg descobriu que a str.translate()
função é muito lenta em comparação com o bytes.translate
, ele levantou um problema , afirmando que:
Em Python 3, str.translate()
geralmente é uma pessimização de desempenho, não otimização.
Por que foi str.translate()
lento?
O principal motivo de str.translate()
ser muito lento era que a pesquisa costumava estar em um dicionário Python.
O uso de maketrans
piorou o problema. A abordagem semelhante usando bytes
cria uma matriz C de 256 itens para consulta rápida de tabela. Portanto, o uso de Python de nível superior dict
torna o str.translate()
Python 3.4 muito lento.
O que aconteceu agora?
A primeira abordagem foi adicionar um pequeno patch, translate_writer . No entanto, o aumento de velocidade não foi tão agradável. Logo outro patch fast_translate foi testado e produziu resultados muito bons de até 55% de aumento de velocidade.
A principal mudança, conforme pode ser visto no arquivo, é que a pesquisa de dicionário Python foi alterada para uma pesquisa de nível C.
As velocidades agora são quase as mesmas que bytes
unpatched patched
str.translate 4.55125927699919 0.7898181750006188
str.translate from bytes trans 1.8910855210015143 0.779950579000797
Uma pequena observação aqui é que o aprimoramento de desempenho só é proeminente em strings ASCII.
Como JFSebastian menciona em um comentário abaixo, Antes de 3.5, a tradução costumava funcionar da mesma maneira para casos ASCII e não ASCII. No entanto, a partir de 3,5 o caso ASCII é muito mais rápido.
Anteriormente, ASCII vs não-ascii costumava ser quase o mesmo, mas agora podemos ver uma grande mudança no desempenho.
Pode ser uma melhoria de 71,6 μs para 2,33 μs, conforme visto nesta resposta .
O código a seguir demonstra isso
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
Tabulação dos resultados:
Python 3.4 Python 3.5
Ascii 91.2 2.3
Unicode 101 117
dict.fromkeys(ord(c) for c in '@#$')
:?