Estaba tratando de eliminar los caracteres no deseados de una cadena dada usando text.translate()
Python 3.4.
El código mínimo es:
import sys
s = 'abcde12345@#@$#%$'
mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$')
print(s.translate(mapper))
Funciona como se esperaba. Sin embargo, el mismo programa cuando se ejecuta en Python 3.4 y Python 3.5 da una gran diferencia.
El código para calcular los tiempos es
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)"
El programa Python 3.4 toma 1.3ms mientras que el mismo programa en Python 3.5 toma solo 26.4μs .
¿Qué ha mejorado en Python 3.5 que lo hace más rápido en comparación con Python 3.4?
python
string
python-3.x
python-internals
python-3.5
Bhargav Rao
fuente
fuente
dict.fromkeys(ord(c) for c in '@#$')
:?Respuestas:
TL; DR - NÚMERO 21118
La larga historia
Josh Rosenberg descubrió que la
str.translate()
función es muy lenta en comparación con elbytes.translate
, planteó un problema , afirmando que:¿Por qué fue
str.translate()
lento?La principal razón para
str.translate()
ser muy lento era que la búsqueda solía realizarse en un diccionario de Python.El uso de
maketrans
empeoró este problema. El enfoque similar que utilizabytes
crea una matriz C de 256 elementos para una búsqueda rápida en la tabla. Por lo tanto, el uso de Python de nivel superiordict
hace questr.translate()
en Python 3.4 sea muy lento.¿Que ha pasado ahora?
El primer enfoque fue agregar un pequeño parche, translate_writer . Sin embargo, el aumento de velocidad no fue tan agradable. Pronto se probó otro parche fast_translate y arrojó muy buenos resultados de hasta un 55% de aceleración.
El cambio principal, como se puede ver en el archivo, es que la búsqueda del diccionario de Python se cambia a una búsqueda de nivel C.
Las velocidades ahora son casi las mismas que
bytes
Una pequeña nota aquí es que la mejora del rendimiento solo es prominente en las cadenas ASCII.
Como menciona JFSebastian en un comentario a continuación, antes de 3.5, la traducción solía funcionar de la misma manera tanto para casos ASCII como no ASCII. Sin embargo, a partir de 3.5 ASCII el caso es mucho más rápido.
Anteriormente, ASCII frente a no ascii solía ser casi lo mismo, sin embargo, ahora podemos ver un gran cambio en el rendimiento.
Puede ser una mejora de 71,6 μs a 2,33 μs como se ve en esta respuesta .
El siguiente código demuestra esto
Tabulación de los resultados:
fuente
55
%: como muestra su respuesta, la aceleración puede ser1000
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)"
(no ascii). Este último es mucho (10 veces) más lento..translate()
, es decir, el caso ascii es mucho más rápido solo en Python 3.5 (no necesitabytes.translate()
rendimiento allí).