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:

  1. El tipo de excepción except sin excepción (línea 5) detectará incluso las excepciones correctas, incluido KeyboardInterrupt . Eso evitará que el programa salga en algunos casos.
  2. 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 porque res era una lista vacía.
  3. Lo peor de todo, si nos preocupaba que el resultado estuviera vacío, hemos causado algo mucho peor. Si get_result falla, la res permanecerá completamente sin configurar, y la referencia a la res 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



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow