【问题标题】:Error handlers in pythonpython中的错误处理程序
【发布时间】:2014-06-17 18:41:50
【问题描述】:

我很难找到“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。
  • 请贴出真实代码的链接,根据抽象样本很难给出准确的建议

标签: python error-handling refactoring try-except contextmanager


【解决方案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

【讨论】:

  • 谢谢!!!这正是我正在寻找的。我知道隐藏错误处理在 python 中是一种不好的做法。但是我需要在项目的大约 30 个点中重复一个长的 try-except 块(大约 40 行)。出于可维护性的原因,我不需要一次又一次地重复这个块。
  • 会说,在with-block之后使用with引入的变量是不好的习惯。这就像在外部使用 for 变量一样。要获得更好的界面,您可以使用 __nonzero__ 而不是 caughtError,顺便说一句,它不符合 pep8。
【解决方案2】:

看不到将无异常信息返回给调用者的方法。您只能将错误处理放在单独的函数中

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

【讨论】:

  • 好主意!我没有想到在外部函数中分离错误处理
  • 很有帮助,但是 Python 的座右铭是“显式优于隐式”,在使用“分离”错误处理程序时请记住这一点。此外,这样的错误处理程序不能影响给定函数/块的局部变量。我需要一个很好的理由(大量重复)来接受这种风格。
【解决方案3】:

从根本上说,你想让你的错误传播,所以不要说:

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)

并让调用者处理错误。

这种方法通常称为Crash Early

【讨论】:

    猜你喜欢
    • 2016-08-18
    • 2013-11-03
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多