return finally 子句中的值是否错误

Is it an error to return a value in a finally clause

如果我尝试下面的代码,我发现普通块 return 的值不是 returned,但最终块 return 的值是:

>>> def f():
...     try:
...         return "normal"
...     finally:
...         return "finally"
... 
>>> f()
'finally'

一个更高级的例子是在每个return语句中调用一个函数:

在那种情况下,我可以看到:

>>> def show(x):
...     print(x)
...     return x
... 
>>> def g():
...     try:
...         return show("normal")
...     finally:
...         return show("finally")
... 
>>> g()
normal
finally
'finally'

在 finally 子句中使用 return 语句是一种好习惯吗? 或者,这是一个潜在的错误(应该通过代码分析工具或代码审查来检测)?

编辑

另一个例外的例子:

>>> def f():
...     try:
...         raise ValueError("bad")
...     finally:
...         return "good"
... 
>>> f()
'good'

奇怪!

如果您 运行 脚本同时包含印刷品,会更容易理解。它表明它实际上进入 try 块内部执行所有操作(实际上几乎 returns),只有 finally 部分覆盖第一个 return 语句。

>>> def f():
...     try:
...             print("try")
...             return "try"
...     finally:
...             print("finally")
...             return "finally"
...
>>> f()
try
finally
'finally'

这是一个好习惯吗?我认为有时这是必要的,我认为这没有任何问题。执行时的 finally 块也会释放资源和其他东西,所以我看不出这是错误的原因。 (我不会说这是一个好的做法,但它没有错。)

在我看来,在 finally 子句中使用 return 语句不是最佳做法,因为要 returned 的值始终是 finally 子句中的值。

如果您想 始终 return 相同的值而不管函数的功能如何,这可能是最佳实践。

进行评估是因为您 运行 python shell 中的此代码。

在 return 情况下,我认为最佳做法是仅使用 tryexcept

def myfunc(x):
    try:
        return x / 0

    except:
        return x

a = myfunc(20)
print(a)

恕我直言,如果在相关的 tryexcept 块中有 return 语句,那么在 finally 子句中使用 return 是不好的做法.

try:
    # lots of spaghetti code
    return fancy_expression_with_side_effects
except AllKindsOfError:
    # lots of alternative spaghetti code
finally:
    # many a mouse wheel spin down the module
    # lots of clean up
    return eternal_return_value

虽然这会构成有效 Python,但实际上不应该。第一个 return 语句将 部分 执行:您将观察评估 fancy_expression_with_side_effects 的副作用(在那里尝试 return print('foo') )并且它仍然 not return 该表达式的值。在那种情况下,我曾经摸不着头脑几个小时。

但是,如果 finally 中的 return 语句是唯一的 return 语句,则可以很容易地遵循分步执行流程简单的预期方式,我没有看到太多错误,但仍然会非常小心: 在许多软件项目中,您可能是了解这些东西的资深 Python 人,但是您有什么保证以后不会有人在其他地方添加 return 语句?