Python中的错误处理程序

4
我有一个问题,就是想找到一种“Pythonic”的方法来解决这个问题: 我需要使用相同的try-except模式捕获不同的代码块。 需要捕获的代码块彼此不同。 目前,我在代码中的多个点上重复使用相同的try-except模式,并列出了一长串异常。
try:
    block to catch
except E1, e:
    log and do something
except E2, e:
    log and do something
...
except Exception, e:
    log and do something

使用 with 语句上下文管理器装饰器 可以很好地解决这个问题:

from contextlib import contextmanager

@contextmanager
def error_handler():
    try:
        yield
    except E1, e:
        log and do something
    ...
    except Exception, e:
        log and do something


...
with error_handler():
    block to catch
...

但是,如果我需要知道块中是否出现异常,该怎么办?也就是说,try-except-else 有没有类似之前 with block 的替代方案呢?

下面是一个使用案例:

for var in vars:
    try:
        block to catch
    except E1, e:
        log and do something
        # continue to the next loop iteration
    except E2, e:
        log and do something
        # continue to the next loop iteration
    ...
    except Exception, e:
        log and do something
        # continue to the next loop iteration
    else:
        do something else

我能用Python的方式进行类似的操作来避免重复使用相同的try-except模式吗?

是的,那就是“Pythonic”的风格,异常处理遵循try-{exceptions...}-else-finally的模式。 - Paul Rigor
请提供真实代码的链接,基于抽象示例很难给出确切的建议。 - Dima Tisnek
3个回答

1
无法找到将无异常信息返回给调用者的方法。您只能将错误处理放在单独的函数中。
def error_handler(exception):
    if isinstance(exception, E1):
        log and do something
    elif isinstance(exception, E2):
    ...
    else:
        log and do something

try:
    block to catch
except Exception, e:
    error_handler(e)
else:
    do something else

好主意!我没有想到将错误处理分离到外部函数中。 - Garet
虽然有帮助,但 Python 的座右铭是“显式优于隐式”,在使用“分离”的错误处理程序时请记住这一点。此外,这种错误处理程序不能影响给定函数/块的本地变量。我需要一个非常好的理由(大量节省重复)才能接受这种风格。 - Dima Tisnek

1

我看到你已经得到了一个答案,但是基于你已有的内容,你可以返回一个指示错误状态的对象,并在循环中使用它进行检查。

不过,在使用这种风格之前,你应该认真考虑是否真的想要在这种结构中隐藏错误处理/日志记录,"Pythonic" 通常更倾向于明确表示而不是隐藏细节。

from contextlib import contextmanager

@contextmanager
def error_handler():
    error = True
    try:
        class Internal:
            def caughtError(self): return error
        yield Internal()
    except Exception as e:
        print("Logging#1")
    except BaseException as e:
        print("Logging#2")
    else:
        error = False

with error_handler() as e:
    print("here")
#    raise Exception("hopp")

print(e.caughtError())         # True if an error was logged, False otherwise

1
谢谢!这正是我在寻找的。我知道在Python中隐藏错误处理是一种不好的做法。但是,我需要在项目的大约30个点上重复一个长的try-except块(大约40行)。出于可维护性的原因,我不想一遍又一遍地重复这个块。 - Garet
使用 with 引入的变量在 with 块之后使用是一个不好的习惯,就像在循环外部使用循环变量一样。为了更好的接口,您可以使用 __nonzero__ 代替 caughtError,顺便说一下,它不符合 pep8 规范。 - Daniel

0

从根本上讲,您希望让错误传播,因此不是像这样说:

def foo():
    try:
        something = xxx
    except ValueError as e:
        logging.warn("oh noes %s", e)
        return 42
    except IndexError as e:
        logging.warn("on no, not again %s", e)
        return 43

    go.on(something=something)

这样怎么样:
def foo():
    try:
        something = xxx
    except Exception:
        logging.exception("oh noes")
        return

    go.on(something=something)

然后也许可以进一步简化:

def foo():
    go.on(something=xxx)

让调用者处理错误。

这种方法通常被称为尽早崩溃


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