Eu estava tentando remover caracteres indesejados de uma determinada string usando text.translate()
Python 3.4.
O código mínimo é:
import sys
s = 'abcde12345@#@$#%$'
mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$')
print(s.translate(mapper))
Funciona como esperado. No entanto, o mesmo programa quando executado em Python 3.4 e Python 3.5 oferece uma grande diferença.
O código para calcular os tempos é
python3 -m timeit -s "import sys;s = 'abcde12345@#@$#%$'*1000 ; mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$'); " "s.translate(mapper)"
O programa Python 3.4 leva 1,3 ms, enquanto o mesmo programa em Python 3.5 leva apenas 26,4 μs .
O que melhorou no Python 3.5 que o torna mais rápido em comparação com o Python 3.4?
python
string
python-3.x
python-internals
python-3.5
Bhargav Rao
fonte
fonte
dict.fromkeys(ord(c) for c in '@#$')
:?Respostas:
TL; DR - ISSUE 21118
A longa história
Josh Rosenberg descobriu que a
str.translate()
função é muito lenta em comparação com obytes.translate
, ele levantou um problema , afirmando que: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 usandobytes
cria uma matriz C de 256 itens para consulta rápida de tabela. Portanto, o uso de Python de nível superiordict
torna ostr.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
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
Tabulação dos resultados:
fonte
55
%: como mostra sua resposta, a velocidade pode ser de1000
s% .python3.5 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
(ascii) vs.python3.5 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
(não-ascii). O último é muito (10x) mais lento..translate()
, ou seja, o caso ascii é muito mais rápido apenas no Python 3.5 (você não precisabytes.translate()
de desempenho lá).