Tengo una declaración if-elif-elif-else en la que el 99% de las veces, se ejecuta la declaración else:
if something == 'this':
doThis()
elif something == 'that':
doThat()
elif something == 'there':
doThere()
else:
doThisMostOfTheTime()
Esta construcción se hace mucho , pero dado que repasa todas las condiciones antes de llegar a las demás, tengo la sensación de que no es muy eficiente, y mucho menos Pythonic. Por otro lado, necesita saber si se cumple alguna de esas condiciones, por lo que debería probarlo de todos modos.
¿Alguien sabe si esto se podría hacer de manera más eficiente y cómo hacerlo o es simplemente la mejor manera de hacerlo?
python
performance
if-statement
kramer65
fuente
fuente
sort
las cosas en las que está ejecutando su if / else ... encadenar, de modo que todos los elementos con los que una de las condiciones coincidirá estén en un extremo y el resto en el otro? Si es así, puede ver si es más rápido / más elegante o no. Pero recuerde, si no hay problemas de rendimiento, es demasiado pronto para preocuparse por la optimización.if not something.startswith("th"): doThisMostOfTheTime()
y hacer otra comparación en laelse
cláusula.something
, o se realizan comparaciones similares varias veces en el mismo valor?Respuestas:
El código...
... parece que debería ser más rápido, pero en realidad es más lento que el
if
...elif
...else
constructo, porque tiene que llamar a una función, que puede ser una sobrecarga de rendimiento significativa en un bucle cerrado.Considere estos ejemplos ...
1.py
2.py
3.py
4.py
... y observe la cantidad de tiempo de CPU que usan ...
... usando el tiempo de usuario de
time(1)
.La opción n. ° 4 tiene la sobrecarga de memoria adicional de agregar un nuevo elemento por cada error de clave distinto, por lo que si espera una cantidad ilimitada de errores de clave distintos, optaría por la opción n. ° 3, que sigue siendo una mejora significativa en la construcción original.
fuente
dict
es más lento, pero tus tiempos realmente muestran que es la segunda opción más rápida.dict.get()
es más lento, que es2.py
el más lento de todos.Crearía un diccionario:
Ahora usa solo:
Si
something
no se encuentra en eloptions
dictdict.get
, devolverá el valor predeterminadodoThisMostOfTheTime
Algunas comparaciones de tiempo:
Guión:
Resultados:
Para
10**5
claves inexistentes y 100 claves válidas:Entonces, para un diccionario normal, la verificación de la clave
key in options
es la forma más eficiente aquí:fuente
options = collections.defaultdict(lambda: doThisMostOfTheTime, {'this': doThis,'that' :doThat, 'there':doThere}); options[something]()
es marginalmente más eficiente.options
dict para evitar reconstruirlo, moviendo así parte (pero no toda) de la lógica lejos del punto de uso. Aún así, ¡buen truco!try: options[key]() except KeyError: doSomeThingElse()
(yaif key in options: options[key]()
que está buscando en el diccionario dos veceskey
¿Puedes usar pypy?
Mantener su código original pero ejecutarlo en pypy me da una aceleración de 50 veces.
CPython:
Pypy:
fuente
Aquí un ejemplo de un if con condiciones dinámicas traducido a un diccionario.
Es una forma, pero puede que no sea la forma más pitónica de hacerlo porque es menos legible para quien no domina Python con fluidez.
fuente
La gente advierte
exec
por razones de seguridad, pero este es un caso ideal para ello.Es una máquina de estado fácil.
fuente