从父函数返回而不引发异常的上下文管理器

时间:2014-05-04 17:41:42

标签: python python-2.7 dry contextmanager

在处理异常时,上下文管理器能否导致它所在的函数为return

我有一些尝试 - 除了我正在写的几种方法常见的模式,我希望用上下文管理器来干掉它。如果存在Exception,则该函数需要停止处理。

以下是我当前实施的一个示例:

>>> class SomeError(Exception):
...     pass
... 
>>> def process(*args, **kwargs):
...     raise SomeError
... 
>>> def report_failure(error):
...     print('Failed!')
... 
>>> def report_success(result):
...     print('Success!')
... 
>>> def task_handler_with_try_except():
...     try:
...         result = process()
...     except SomeError as error:
...         report_failure(error)
...         return
...     # Continue processing.
...     report_success(result)
... 
>>> task_handler_with_try_except()
Failed!

有没有办法干掉try-except,以便在SomeError被引发时返回任务处理函数?

注意:任务处理程序由库中的代码调用,该代码不处理从任务处理函数生成的异常。

这是一次尝试,但会导致UnboundLocalError

>>> import contextlib
>>> @contextlib.contextmanager
... def handle_error(ExceptionClass):
...     try:
...         yield
...     except ExceptionClass as error:
...         report_failure(error)
...         return
... 
>>> def task_handler_with_context_manager():
...     with handle_error(SomeError):
...         result = process()
...     # Continue processing.
...     report_success(result)
... 
>>> task_handler_with_context_manager()
Failed!
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 6, in task_handler_with_context_manager
UnboundLocalError: local variable 'result' referenced before assignment

是否可以使用上下文管理器来干掉这种模式,还是有替代方案?

1 个答案:

答案 0 :(得分:1)

不,上下文管理员无法做到这一点,因为您只能return来自其正文中的函数。

但是,您正在寻找的东西确实存在!它被称为装饰者。

def handle_errors(func):
    def inner(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except SomeError as error:
            report_failure(error)
            return
    return inner

@handle_errors
def task_handler():
    result = process()
    report_success(result)

请注意,如果您一直想要report_success,那么您可以进一步干掉它!

def report_all(func):
    def inner(*args, **kwargs):
        try:
            ret = func(*args, **kwargs)
            report_success(ret)
            return ret
        except SomeError as error:
            report_failure(error)
            return
    return inner

@report_all
def task_handler():
    return = process()

你根本不需要任务处理程序:

@report_all
def process():
    # ...