长期异常链的优雅替代品?

时间:2018-04-20 18:46:43

标签: python

很多时候我发现自己写的东西看起来像这样:

try:
    procedure_a()
except WrongProcedureError:
    try:
        procedure_b()
    except WrongProcedureError:
        try:
            procedure_c()
        except WrongProcedureError:
            give_up()

这很可怕。是否有更优雅的方式来实现这种“尝试直到一个不例外”的逻辑?看起来这种事情会出现很多;我希望有一些语言功能,我不知道这是为这个确切的东西设计的。

3 个答案:

答案 0 :(得分:22)

您可以使用for/else构造:

for proc in [procedure_a, procedure_b, procedure_c]:
    try:
        proc()
    except WrongProcedureError:
        continue
    else:
        break
else:
    give_up()

else循环的for子句仅在控件自然脱离for子句的底部时触发。如果您break出局(如果三个程序中的任何一个没有抛出异常,那么它就不会被触发)。

答案 1 :(得分:5)

循环程序。将循环包装成一个函数。在成功的情况下过早地从函数返回:

def try_all():
    for procedure in [procedure_a, procedure_b, procedure_c]:
        try:
            procedure()
            return
        except WrongProcedureError:
            continue
    give_up()

答案 2 :(得分:3)

实际上你的方法并没有错。它使用普通语言功能并传达其信息非常清晰。

其他方法也有效,但理解起来有些复杂,可能只有在你想要检查的功能很多(不仅仅是3个)时才会更好。在那种情况下,我实际上会创建一个函数来隐藏这种复杂性。

import itertools
from contextlib import suppress

def call_functions(funcs, give_up_func):
    for func in itertools.chain(funcs, [give_up_func]):
        with suppress(WrongProcedureError):
            func()
            return  # only reached when func does not raise WrongProcedureError.

假设give_up_func不会引发异常而suppress需要python 3(我认为3.4)。

但是,实际需要时,代码中可能存在根本错误。这似乎是某种“后备”操作,可能应该使用子类或其他参数或策略/工厂而不是嵌套的tryexcept来解决。