Python Language
Anti-patrones de Python
Buscar..
Con exceso de celo excepto la cláusula
Las excepciones son poderosas, pero una sola cláusula exagerada puede quitarlo todo en una sola línea.
try: res = get_result() res = res[0] log('got result: %r' % res) except: if not res: res = '' print('got exception')
Este ejemplo demuestra 3 síntomas del antipattern:
- El tipo de excepción
except
sin excepción (línea 5) detectará incluso las excepciones correctas, incluidoKeyboardInterrupt
. Eso evitará que el programa salga en algunos casos. - El bloque de excepción no vuelve a generar el error, lo que significa que no podremos saber si la excepción provino de
get_result
o porqueres
era una lista vacía. - Lo peor de todo, si nos preocupaba que el resultado estuviera vacío, hemos causado algo mucho peor. Si
get_result
falla, lares
permanecerá completamente sin configurar, y la referencia a lares
en el bloque de excepción, generaráNameError
,NameError
completamente el error original.
Siempre piensa en el tipo de excepción que estás tratando de manejar. Dale una lectura a la página de excepciones y comprueba qué excepciones básicas existen.
Aquí hay una versión fija del ejemplo anterior:
import traceback try: res = get_result() except Exception: log_exception(traceback.format_exc()) raise try: res = res[0] except IndexError: res = '' log('got result: %r' % res)
Capturamos excepciones más específicas, volviendo a subir cuando sea necesario. Unas líneas más, pero infinitamente más correctas.
Mirando antes de saltar con la función de procesador intensivo
Un programa puede fácilmente perder tiempo llamando a una función intensiva en el procesador varias veces.
Por ejemplo, tome una función que se parece a esto: devuelve un entero si el value
entrada puede producir uno, de lo contrario, None
:
def intensive_f(value): # int -> Optional[int]
# complex, and time-consuming code
if process_has_failed:
return None
return integer_output
Y podría ser utilizado de la siguiente manera:
x = 5
if intensive_f(x) is not None:
print(intensive_f(x) / 2)
else:
print(x, "could not be processed")
print(x)
Si bien esto funcionará, tiene el problema de llamar intensive_f
, que duplica el tiempo de ejecución del código. Una mejor solución sería obtener el valor de retorno de la función de antemano.
x = 5
result = intensive_f(x)
if result is not None:
print(result / 2)
else:
print(x, "could not be processed")
Sin embargo, una forma más clara y posiblemente más pirónica es usar excepciones, por ejemplo:
x = 5
try:
print(intensive_f(x) / 2)
except TypeError: # The exception raised if None + 1 is attempted
print(x, "could not be processed")
Aquí no se necesita una variable temporal. Puede ser a menudo preferible utilizar una assert
declaración, y para coger el AssertionError
lugar.
Claves del diccionario
Un ejemplo común de dónde se puede encontrar esto es acceder a las claves del diccionario. Por ejemplo comparar:
bird_speeds = get_very_long_dictionary()
if "european swallow" in bird_speeds:
speed = bird_speeds["european swallow"]
else:
speed = input("What is the air-speed velocity of an unladen swallow?")
print(speed)
con:
bird_speeds = get_very_long_dictionary()
try:
speed = bird_speeds["european swallow"]
except KeyError:
speed = input("What is the air-speed velocity of an unladen swallow?")
print(speed)
El primer ejemplo tiene que mirar el diccionario dos veces, y como este es un diccionario largo, puede llevar mucho tiempo hacerlo cada vez. El segundo solo requiere una búsqueda en el diccionario y, por lo tanto, ahorra mucho tiempo de procesador.
Una alternativa a esto es usar dict.get(key, default)
, sin embargo, muchas circunstancias pueden requerir operaciones más complejas en el caso de que la clave no esté presente