python try except 作为计算表达式的函数

Vic*_* Sg 4 python python-3.x try-except

我尝试创建一个函数来尝试表达式并在出现错误时返回零。

def try_or_zero(exp):
    try:
        exp
        return exp
    except:
        return 0
Run Code Online (Sandbox Code Playgroud)

这显然是行不通的。问题似乎在于 python 没有任何形式的惰性求值,因此表达式在传递给函数之前会被求值,因此它会在进入函数之前引发错误,因此它永远不会通过 try 逻辑。有谁知道这是否可以在Python中完成?干杯

bru*_*ers 5

问题似乎是 python 没有任何形式的惰性求值

呃……是的,确实如此,但可能不是您期望的形式。函数参数在传递给函数之前确实已被评估,所以

try_or_zero(foo.bar())
Run Code Online (Sandbox Code Playgroud)

确实会被执行为:

param = foo.bar()
try_or_zero(param)
Run Code Online (Sandbox Code Playgroud)

现在Python函数是普通对象(它们可以用作变量,作为参数传递给函数等),并且它们仅在应用调用运算符(括号,带或不带参数)时被调用,因此您可以将函数传递给try_or_zero和让我们try_or_zero调用该函数:

def try_or_zero(func):
    try:
        return func()
    except Exception as e:
        return 0
Run Code Online (Sandbox Code Playgroud)

现在你要反对 1/ 如果函数需要参数,这将不起作用;2/ 必须为此编写一个函数,这是 PITA - 并且这两种反对意见都是有效的。希望 Python 也有一个快捷方式来创建由单个(即使任意复杂)表达式组成的简单匿名函数:lambda。此外,Python 函数(包括“lambda 函数”——从技术上讲,它们是普通函数)是闭包——它们捕获定义它们的上下文——因此很容易将所有这些包装在一起:

a = 42
b = "c"

def add(x, y):
    return x + y

result = try_or_zero(lambda: add(a, b))
Run Code Online (Sandbox Code Playgroud)

关于异常处理的附注:

首先不要使用裸露的 except,至少要使用 catch Exception(否则你可能会阻止一些异常 - 比如SysExit- 按预期工作)。

另外最好只捕获您在给定点期望的确切异常。在您的情况下,您可能需要传递一个要忽略的异常元组,即:

def try_or_zero(func, *exceptions):
    if not exceptions:
        exceptions = (Exception,)  
    try:
        return func()
    except exceptions as e:
        return 0


a = 42
b = "c"

def add(x, y):
    return x + y

result = try_or_zero(lambda: add(a, b), TypeError))
Run Code Online (Sandbox Code Playgroud)

这将防止您的代码掩盖意外错误。

最后:您可能还想在异常情况下添加对非零返回值的支持(并非所有表达式都应该返回 int ):

# XXX : python3 only, python2 doesn't accept
# keyword args after *args

def try_or(func, *exceptions, default=0):
    if not exceptions:
        exceptions = (Exception,)  
    try:
        return func()
    except exceptions as e:
        return default

# adding lists is legit too,
# so here you may want an empty list as the return value
# instead
a = [1, 2, 3]
# but only to lists
b = ""

result = try_or(lambda: a + b, TypeError, default=[]))
Run Code Online (Sandbox Code Playgroud)