Python 定义 IFERROR 函数

Kal*_*icq 5 python exception

我正在尝试像在 Excel 中一样在 python 中定义我自己的 IFERROR 函数。(是的,我知道我可以编写 try/ except 。我只是想为我经常使用的 try/ except 模式创建一个内联简写。)当前的用例是尝试获取一些远程表的几个属性。用于连接到它们的模块会给出各种错误,如果发生这种情况,我只想记录在尝试获取该属性时遇到的错误。

我尝试过的:搜索显示了许多线程,其中最有用的是:

Python 中频繁重复的 try/ except

Python:try- except 作为表达式?

阅读这些主题后,我尝试编写以下内容:

>>> def iferror(success, failure, *exceptions):
...     try:
...         return success
...     except exceptions or Exception:
...         return failure
...
>>> iferror(1/0,0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
Run Code Online (Sandbox Code Playgroud)

我还尝试使用上下文管理器(对我来说是新的):

>>> from contextlib import contextmanager as cm
>>> @cm
... def iferror(failure, *exceptions):
...     try:
...         yield
...     except exceptions or Exception:
...         return failure
...
>>> with iferror(0,ZeroDivisionError) as x:
...     x=1/0
...
>>> print(x)
None
Run Code Online (Sandbox Code Playgroud)

有没有办法定义一个函数来执行像 IFERROR 这样的预定义 try/ except 模式?

mel*_*ene 6

问题iferror(1/0,0)是函数参数在输入函数之前就被求值了(大多数编程语言都是这种情况,唯一的一个例外是 Haskell)。无论iferror做什么,1/0都会先运行并抛出错误。

我们必须以某种方式延迟评估,1/0以便它发生在函数内部、try块的上下文中。一种方法是使用 string( iferror('1/0', 1)) ,iferror然后可以eval. 但eval应该尽可能避免,并且有一个更轻量级的替代方案:在调用函数之前不会评估函数体,因此我们可以将表达式包装在函数中并传递:

def iferror(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure

def my_expr():
    return 1/0

print(iferror(my_expr, 42))
Run Code Online (Sandbox Code Playgroud)
def iferror(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure

def my_expr():
    return 1/0

print(iferror(my_expr, 42))
Run Code Online (Sandbox Code Playgroud)

这里的关键部分是我们不my_expr直接调用。我们将它作为函数传递给iferror,然后调用success(),最终执行return 1/0

唯一的问题是我们必须将函数参数 ( 1/0) 从正常的代码流中取出并放入一个单独的函数定义中,我们必须给它一个名称(即使它只使用一次)。

这些缺点可以通过使用来避免lambda,它允许我们内联定义单表达式函数:

def iferror(success, failure, *exceptions):
    try:
        return success()
        #             ^^
    except exceptions or Exception:
        return failure

print(iferror(lambda: 1/0, 42))
#             ^^^^^^^
Run Code Online (Sandbox Code Playgroud)
42
Run Code Online (Sandbox Code Playgroud)

[现场演示]

与您最初的尝试相比,只需要进行两处更改:将表达式包装在 a 中lambda:,这会延迟求值,并使用()intry: return success()调用 lambda,这会触发函数体的求值。