Parfois, je me trouve dans la situation où je veux exécuter plusieurs commandes séquentielles comme celles-ci:
try:
foo(a, b)
except Exception, e:
baz(e)
try:
bar(c, d)
except Exception, e:
baz(e)
...
Ce même modèle se produit lorsque les exceptions doivent simplement être ignorées.
Cela semble redondant et la syntaxe excessive le rend étonnamment difficile à suivre lors de la lecture de code.
En C, j'aurais résolu ce type de problème facilement avec une macro, mais malheureusement, cela ne peut pas être fait en python pur.
Question: Comment puis-je réduire au mieux l'encombrement du code et augmenter la lisibilité du code lorsque je rencontre ce modèle?
Vous pouvez utiliser l'instruction with
si vous avez python 2.5 ou supérieur:
from __future__ import with_statement
import contextlib
@contextlib.contextmanager
def handler():
try:
yield
except Exception, e:
baz(e)
Votre exemple devient maintenant:
with handler():
foo(a, b)
with handler():
bar(c, d)
Si c'est toujours, toujours le comportement que vous voulez quand une fonction particulière lève une exception, vous pouvez utiliser un décorateur:
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)
Usage:
>>> foo(1, '2')
unsupported operand type(s) for +: 'int' and 'str'
>>> bar('steve', 'cheese')
substring not found
S'il s'agit de commandes simples d'une seule ligne, vous pouvez les encapsuler dans lambda
s:
for cmd in [
(lambda: foo (a, b)),
(lambda: bar (c, d)),
]:
try:
cmd ()
except StandardError, e:
baz (e)
Vous pouvez envelopper tout cela dans une fonction, donc cela ressemblait à ceci:
ignore_errors (baz, [
(lambda: foo (a, b)),
(lambda: bar (c, d)),
])
Vous pouvez essayer quelque chose comme ça. Cela ressemble vaguement à une macro C.
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 )
La meilleure approche que j'ai trouvée est de définir une fonction comme celle-ci:
def handle_exception(function, reaction, *args, **kwargs):
try:
result = function(*args, **kwargs)
except Exception, e:
result = reaction(e)
return result
Mais cela ne semble tout simplement pas correct dans la pratique:
handle_exception(foo, baz, a, b)
handle_exception(bar, baz, c, d)