2012-02-21 8 views
11

He creado un conjunto de funciones y necesito cláusulas excepcionales muy similares en todas ellas, pero odio tener tantas líneas de cláusulas try y except y el mismo código dentro de cada función. Por ejemplo:Repetitive Try y Except Clauses

import sys 
import random 

def foo(): 
    num=random.random() 
    try: 
     if num>0.5: print 'OK' 
     elif num>0.25: raise NameError('Too Small') 
     else: raise KeyboardInterrupt 
    except NameError: 
     print "%s had a NameError" % sys._getframe().f_code.co_name 
    except: 
     print "%s had a different Error" % sys._getframe().f_code.co_name 

def bar(): 
    num=random.random() 
    try: 
     if num>0.8: print 'OK' 
     elif num>0.6: raise NameError('Too Small') 
     else: raise KeyboardInterrupt 
    except NameError: 
     print "%s had a NameError" % sys._getframe().f_code.co_name 
    except: 
     print "%s had a different Error" % sys._getframe().f_code.co_name 

El código después de "probar" es diferente para las funciones, pero el código después de "excepción" es la misma. Quiero consolidar esas declaraciones excepto para que mi código no se vea tan estrecho. ¿Existe una forma correcta de hacer esto?

+1

Capturar cualquier excepción suele ser una muy mala idea. Enmascara problemas reales y dificulta la depuración. Captura las excepciones que conozcas, si no las conoces, ¿realmente quieres atraparlas? –

+0

Ese es un buen punto. Si la función falla, necesito la secuencia de comandos para seguir adelante. El último "excepto" incluye 'print sys.exc_info() [: 2]' que incluye el nombre de la excepción. ¿Hay una mejor manera de hacer esto? – crunkchitis

Respuesta

22

Python Decorators son lo que quieres.

Dijiste que el bloque excepto es siempre el mismo. Crea un decorador personalizado que haga lo que quieras. Tendrás que aplicar esto a cada función/método, pero seguro que salva la duplicación.

def handleError(function): 
    def handleProblems(): 
     try: 
      function() 
     except Exception: 
      print "Oh noes" 
    return handleProblems 


@handleError 
def example(): 
    raise Exception("Boom!") 

Cuando se llama a un método con el decorador aplicados:

 
>>> 
>>> example() 
Oh noes 
>>> 

Usted tendrá que cambiar los tipos de excepción, así como lo que se hace, pero usted consigue la jist de dónde voy con esta.

+0

impresionante. gracias por esto. – crunkchitis

+0

@crunkchitis eres bienvenido. – Finglas

+2

Este no es un buen ejemplo porque el decorador no funcionará para las Funciones que toman un argumento. – user3467349

6

El contenido dentro de tu bloque try es lo interesante, por lo que debería estar en funciones. Luego, simplemente seleccione qué función desea y llámela, envuelta en sus excepciones. Incluso podría escribir el código de excepción como una función, y pasar la función seleccionada a esto como un argumento. p.ej.

def foo(): 
    num=random.random() 
    if num>0.5: print 'OK' 
    elif num>0.25: raise NameError('Too Small') 
    else: raise KeyboardInterrupt 

def bar(): 
    num=random.random() 
    if num>0.8: print 'OK' 
    elif num>0.6: raise NameError('Too Small') 
    else: raise KeyboardInterrupt 

def try_numerics(f): 
    try: 
     f() 
    except NameError: 
     print "%s had a NameError" % sys._getframe().f_code.co_name 
    except: 
     print "%s had a different Error" % sys._getframe().f_code.co_name 

# In your main code... 
if (need_to_run_foo): 
    try_numerics(foo) 
elif (need_to_run_bar): 
    try_numerics(bar) 
2

Si esas son sus funciones reales, sería fácil generalizarlas.

Se puede crear una función general

def general(bottom_num, top_num): 
    num=random.random() 
    try: 
    if num>top_num: print 'OK' 
    elif num>bottom_num: raise NameError('Too Small') 
    else: raise KeyboardInterrupt 
    except NameError: 
    print "%s had a NameError" % sys._getframe().f_code.co_name 
    except: 
    print "%s had a different Error" % sys._getframe().f_code.co_name 

esto sería mantener su código de repetir y abordar el intento: excepto: tema

5

La respuesta anterior no se aplica para las funciones que toman argumentos - para el último caso, pienso que usted quiere algo como esto:

def handleError(f): 
    def handleProblems(*args, **kwargs): 
     try: 
      return f(*args, **kwargs) 
     except Exception: 
      print "Oh noes" 
    return handleProblems 

podemos probar que de este modo:

@handleError 
def addTwo(x, y): 
    print(x + y) 

>>> addTwo(5,5) 
10 
>>> addTwo(5, 's') 
Oh noes 
0

Me encontré con el mismo escenario recientemente, en mi caso tengo algunas excepciones personalizadas basadas en las cuales necesito iniciar sesión o aumentar aún más la excepción. Creé un método de decorador para manejar las excepciones según el tipo.

try: 
    obj.some_method() 
except Exception as e: 
    catch_and_log_exception(e) 


def catch_and_log_exception(e): 
    if isinstance(e, MyConnectionError): 
     print "Connection error : %s." % e.message 
     sys.exit(1) 
    elif isinstance(e, MyConnectionTimeout): 
     print "Connection to server has been timed out. %s" % e.message 
     sys.exit(1) 
    elif isinstance(e, MyException): 
     message = e.explanation if e.explanation else e.message 
     log_error_message(str(message)) 
     print "Failed, please check the logs." 
     sys.exit(1) 
    else: 
     raise e 

Hope this help !!

Cuestiones relacionadas