Python异常控制/流程问题

3

我一直在使用Python编程,遇到了一个可能很普遍的问题。我有五个语句都会出现抛出FooException和BarException的情况。我想要运行每个语句,防止这些异常的发生,但即使在处理后抛出异常,也要继续处理。现在,我可以像这样实现:

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个回答

4
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)

棒极了的代码。一个更简单的实现方法是在函数上进行循环(for fn in (foo, bar, ...)),并使用问题中的代码。但这个execute_silently函数非常整洁。 - Jean-Francois T.

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 

这两种解决方案的问题在于我的语句并不是严格的可调用对象。现在,我可以通过定义函数或lambda使它们成为可调用对象,但这比我上面做的更糟吗? - Brandon Adams
3
最好能展示真正的代码。但一般而言,exec 是一种特殊工具,应该尽量避免使用。 - Cat Plus Plus

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()

这仍然会在第一个异常时停止块的执行,最好直接使用 try - Cat Plus Plus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接