2011-11-15 4 views
3

J'ai travaillé en Python et j'ai rencontré un problème qui doit être commun. J'ai cinq déclarations qui tombent toutes dans un piège commun d'élever FooException et BarException. Je veux exécuter chacun d'entre eux, en gardant contre ces exceptions mais continuant à traiter même si une exception est levée après une certaine manipulation est faite. Maintenant, je pourrais faire comme ceci:Exceptions Python Contrôle/flux Problème

try: 
    foo() 
except (FooException, BarException): 
    pass 
try: 
    bar() 
except (FooException, BarException): 
    pass 
try: 
    baz() 
except (FooException, BarException): 
    pass 
try: 
    spam() 
except (FooException, BarException): 
    pass 
try: 
    eggs() 
except (FooException, BarException): 
    pass 

mais c'est vraiment verbeux et en violation extrême de DRY. est quelque chose comme une solution plutôt force brute et évidente:

def wish_i_had_macros_for_this(statements, exceptions, gd, ld):     
    """ execute statements inside try/except handling exceptions with gd and ld 
    as global dictionary and local dictionary 

    statements is a list of strings to be executed as statements 
    exceptions is a list of strings that resolve to Exceptions 
    gd is a globals() context dictionary 
    ld is a locals() context dictionary 

    a list containing None or an Exception if an exception that wasn't 
    guarded against was raised during execution of the statement for each 
    statement is returned 
    """ 
    s = """ 
try:  
    $STATEMENT 
except (%s): 
    pass 
""" % ','.join(exceptions)              
    t = string.Template(s) 
    code = [t.substitute({'STATEMENT': s}) for s in statements]     
    elist = list() 
    for c in code: 
     try: 
      exec c in gd, ld 
      elist.append(None) 
     except Exception, e: 
      elist.append(e) 
    return elist 

Avec l'utilisation le long des lignes de:

>>> results = wish_i_had_macros_for_this(
       ['foo()','bar()','baz','spam()','eggs()'], 
       ['FooException','BarException'], 
       globals(), 
       locals()) 
[None,None,None,SpamException,None] 

Y at-il une meilleure façon?

Répondre

3

Que pensez-vous de cela?

#!/usr/bin/env python 

def foo(): 
    print "foo" 

def bar(): 
    print "bar" 

def baz(): 
    print "baz" 

for f in [foo, bar, baz]: 
    try: 
     f() 
    except (FooException, BarException): 
     pass 
+0

Le problème avec ces deux solutions est que mes déclarations ne sont pas strictement appelables. Maintenant, je pourrais suivre cela et les rendre appelables en définissant funcs ou lambdas, mais est-ce moins mauvais que ce que je fais ci-dessus? –

+3

@BrandonAdams: ce sera mieux si vous montrez le vrai code. Mais en général, 'exec 'est un outil spécial, et devrait plutôt être évité. –

3
def execute_silently(fn, exceptions = (FooException, BarException)): 
    try: 
     fn() 
    except Exception as e: 
     if not isinstance(e, exceptions): 
      raise 

execute_silently(foo) 
execute_silently(bar) 
# ... 
# or even: 
for fn in (foo, bar, ...): 
    execute_silently(fn) 
0

Cette version permet l'exécution de l'instruction ainsi:

from contextlib import contextmanager 
from functools import partial 

@contextmanager 
def exec_silent(exc=(StandardError,)): 
    try: 
     yield 
    except exc: 
     pass 

silent_foobar = partial(exec_silent, (FooException, BarException)) 

with silent_foobar(): 
    print 'foo' 
    foo() 
with silent_foobar(): 
    print 'bar' 
    bar() 
+0

Cela arrêtera toujours l'exécution du bloc à la première exception, aussi bien utiliser 'try' directement. –