2011-11-15 8 views
3

私はPythonで作業していましたが、共通の問題である必要がありました。 私は、すべてが、 FooExceptionとBarExceptionを発生させる共通の落とし穴に入るという5つの声明を持っています。これらの例外を に対して防御していますが、何らかの処理が行われた後に例外が発生しても処理を継続します。今、私はそうすることができる:Python例外制御/フローの問題

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 

しかし、それは本当に冗長であり、DRYの極端な違反です。線に沿って、使用して

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 

:かなり強引 と明白な解決策は、このようなものである

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

良い方法はありますか?

答えて

3

この点についてはどうですか?

#!/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

これらのソリューションの両方の問題は、私の文は厳密に呼び出し可能ではないということです。さて、私はこれを実行してfuncsやlambdaを定義することで呼び出し可能にすることができますが、これは私が上でやっていることよりも悪いことではありませんか? –

+3

@BrandonAdams:実際のコードを表示すると最適です。しかし、一般に、 'exec'は特殊目的のツールであり、むしろ避けるべきです。 –

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

このバージョンでは、同様のステートメントの実行を許可します。

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

これは最初の例外でブロックの実行を停止しますが、 'try'を直接使用することもできます。 –