使用装饰器用“if func return false,return false”包装所有函数

时间:2016-07-19 12:07:31

标签: python decorator python-decorators

我正在编写一个基于main函数的基本Python脚本,该脚本按顺序调用其他函数。

我想要做的是将main中调用的所有函数包装起来:

result = func(*some_args):
   if (result != True):
       return result

例如,对于此代码:

def func1(arg1 , arg2):
     if (some_cond):
        return False #Or some err_val
     return True

def func2(arg1):
     if (some_cond):
        return False
     return True

def main():
    func1(val1 , val2)
    func2(val3)
    return True

if __name__ == "__main__":
     import sys
     result = main()
     if (result == err_val1):
          # Do something. Maybe print. Maybe call some function.
          sys.exit(1)

我希望如果其中一个函数失败main会中断并返回其错误。我可以使用装饰器吗?

4 个答案:

答案 0 :(得分:2)

我认为最好的解决方案是使用例外。如果这绝对不是你想要的,你可以做一些短路:

return func1() and func2()

将此扩展到更多功能,而不需要and s:

from functools import partial

def main():
    funcs = (partial(func1, arg1, arg2),
             partial(func2, arg1))

    if any(!f() for f in funcs):
        return False

虽然这并没有返回"它的错误" (失败的函数错误),它只返回False。如果你想在不同类型的错误之间做出更多区分......那么,你要回到例外。

答案 1 :(得分:2)

这正是在Python中构建的异常。

removeItem()

答案 2 :(得分:1)

由于你实际上希望程序在发生其中一个错误时死亡,你也可以提升SystemExit。这是使用装饰器完成此操作的方法。

flag = 2

def die_on_not_True(func):
    def wrapper(*args):
        rc = func(*args)
        if rc is not True:
            fmt = 'Function {} failed with return value {!r}'
            print(fmt.format(func.__name__, rc))
            raise SystemExit(1)
        return True
    return wrapper

@die_on_not_True
def func1(arg1 , arg2):
     if arg1 == flag:
        return 'error 1' 
     return True

@die_on_not_True
def func2(arg1):
     if arg1 == flag:
        return 'error 2'
     return True

def main():
    val1, val2, val3 = 1, 2, 3
    print(func1(val1, val2))
    print('one')
    print(func2(val3))
    print('two')


if __name__ == '__main__':
    main()

<强>输出

True
one
True
two

如果我们设置flag = 1,则输出变为

Function func1 failed with return value 'error 1'

如果我们设置flag = 3,则输出变为

True
one
Function func2 failed with return value 'error 2'

flag等于2时,退出状态为0返回给shell,当flag等于1或3时,退出状态为1。

如果您想在打印错误消息后进行进一步处理,请提出自定义异常而不是SystemExit,并通过将main来电包裹在try...except中来抓住它。

答案 3 :(得分:0)

我想,你真正想要的是一个通用异常捕获器,它将捕获并返回任何包装函数的异常。你可以这样轻松地做到这一点。

def return_exception(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            return e
    return wrapper

实施例

In [3]: @return_exception
   ...: def div(a, b):
   ...:     return a / b
   ...: 

In [4]: div(1, 0)
Out[4]: ZeroDivisionError('division by zero')

那么你可以按照你想要的方式处理返回异常对象,虽然很难说你为什么需要它。

更新正如其他人所说,仅捕获特定异常通常会很好。您可以稍微修改装饰器。

def return_exception(*exception_types):
    def build_wrapper(func):
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except exception_types as e:
                return e
        return wrapper
    return build_wrapper

示例:

In [6]: @return_exception(ZeroDivisionError)
   ...: def div(a, b):
   ...:     return a / b
   ...: 

In [7]: div(0, 1)
Out[7]: 0.0

In [8]: div(1, 0)
Out[8]: ZeroDivisionError('division by zero')

In [9]: div(1, "a")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
...
TypeError: unsupported operand type(s) for /: 'int' and 'str'

In [10]: @return_exception(ZeroDivisionError, TypeError)
   ....: def div(a, b):
   ....:     return a / b
   ....: 

In [11]: div(1, 0)
Out[11]: ZeroDivisionError('division by zero')

In [12]: div(1, "a")
Out[12]: TypeError("unsupported operand type(s) for /: 'int' and 'str'")

如您所见,您只捕获指定的异常(但您仍然可以指定通用Exception类。)