2008-09-24 10 views
25

A veces me encuentro en la situación en la que yo quiero para ejecutar varios comandos secuenciales, como por ejemplo:control de excepciones Genérico en Python la "manera correcta"

try: 
    foo(a, b) 
except Exception, e: 
    baz(e) 
try: 
    bar(c, d) 
except Exception, e: 
    baz(e) 
... 

Este mismo patrón se produce cuando excepciones necesitan simplemente ser ignorado.

Esto se siente redundante y la sintaxis excesiva hace que sea sorprendentemente difícil de seguir al leer el código.

En C, habría resuelto este tipo de problema fácilmente con un macro, pero, por desgracia, esto no se puede hacer en python recta.

Pregunta: ¿Cómo puedo reducir la huella del código y aumentar la legibilidad del código al encontrar este patrón?

Respuesta

62

se podría utilizar el with statement si tiene Python 2.5

from __future__ import with_statement 
import contextlib 

@contextlib.contextmanager 
def handler(): 
    try: 
     yield 
    except Exception, e: 
     baz(e) 

Su ejemplo se convierte ahora en:

with handler(): 
    foo(a, b) 
with handler(): 
    bar(c, d) 
4

Si son simples comandos de una línea, se puede envolver en lambda s:

for cmd in [ 
    (lambda: foo (a, b)), 
    (lambda: bar (c, d)), 
]: 
    try: 
     cmd() 
    except StandardError, e: 
     baz (e) 

Usted puede envolver todo el asunto en una función, por lo que parecía ser la siguiente:

ignore_errors (baz, [ 
    (lambda: foo (a, b)), 
    (lambda: bar (c, d)), 
]) 
3

El mejor método que he encontrado, es definir una función como tales:

def handle_exception(function, reaction, *args, **kwargs): 
    try: 
     result = function(*args, **kwargs) 
    except Exception, e: 
     result = reaction(e) 
    return result 

Pero que simplemente no se siente o se ve bien en la práctica:

handle_exception(foo, baz, a, b) 
handle_exception(bar, baz, c, d) 
+5

Puede Simplifique esa función simplemente retornando en lugar de asignar a "resultado". –

-4

En su caso específico, usted puede hacer esto:

try: 
    foo(a, b) 
    bar(c, d) 
except Exception, e: 
    baz(e) 

O bien, puede detectar la excepción de un paso anterior:

try: 
    foo_bar() # This function can throw at several places 
except Exception, e: 
    baz(e) 
+3

Si foo() generó una excepción, bar() no se ejecutará. Ese no es el comportamiento deseado. – Sufian

3

Usted podría intentar algo como esto. Esto es vagamente C en forma de macro.

class TryOrBaz(object): 
    def __init__(self, that): 
     self.that= that 
    def __call__(self, *args): 
     try: 
      return self.that(*args) 
     except Exception, e: 
      baz(e) 

TryOrBaz(foo)(a, b) 
TryOrBaz(bar)(c, d) 
+5

Tu espaciado es horrible. Consulte "Espacios en blanco en expresiones y enunciados" http://www.python.org/dev/peps/pep-0008/ – jfs

+5

No es "horrible". Idiomático y atípico. Y un hábito de 30 años a partir de Pascal y C. No cambia en el corto plazo para eliminar espacios cercanos a() 's.Se necesitan espacios para una infraestructura obsoleta (ojos, principalmente) –

+1

Los hábitos dictan lo que encontramos legible. Otros ojos viejos encuentran los espacios distractores debido a otros hábitos. – Alfe

11

Si esto es siempre, siempre el comportamiento que desea, cuando una determinada función lanza una excepción, se puede usar un decorador:

def handle_exception(handler): 
    def decorate(func): 
     def call_function(*args, **kwargs): 
      try: 
       func(*args, **kwargs) 
      except Exception, e: 
       handler(e) 
     return call_function 
    return decorate 

def baz(e): 
    print(e) 

@handle_exception(baz) 
def foo(a, b): 
    return a + b 

@handle_exception(baz) 
def bar(c, d): 
    return c.index(d) 

Uso:

>>> foo(1, '2') 
unsupported operand type(s) for +: 'int' and 'str' 
>>> bar('steve', 'cheese') 
substring not found 
Cuestiones relacionadas