【问题标题】:Is it an error to return a value in a finally clause [duplicate]在 finally 子句中返回值是否错误[重复]
【发布时间】:2020-02-12 01:44:45
【问题描述】:

如果我尝试下面的代码,我看到没有返回正常的块返回值,但是finally块返回值是:

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

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

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

  • 在普通块中,show 函数被评估(但不返回),
  • 在 finally 块中,评估并返回 show 函数:
>>> 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'

奇怪!

【问题讨论】:

标签: python python-3.x try-finally


【解决方案1】:

恕我直言,如果在相关的 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')),它仍然返回该表达式的价值。在那种情况下,我曾经摸过头几个小时。

但是,如果finally 中的return 语句是唯一的return 语句,那么人们将能够以一种简单的预期方式轻松地遵循逐步执行流程,并且我没有看到太多错误在其中,但仍会非常小心: 在许多软件项目中,你可能是知道这些东西的资深 Python 人,但你有什么保证,以后不会有人在其他地方添加 return 语句?

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 如果在其他地方有 return 声明,我会说这是不好的做法。你会迷惑自己和同事尝试调试正常流程中的返回语句没有错误但神奇地没有执行的代码
    【解决方案3】:

    在我看来,在 finally 子句中包含 return 语句并不是最佳实践,因为要返回的值始终是 finally 子句中的值。

    如果您希望始终返回相同的值而不考虑函数的作用,这可能是最佳做法。

    因为您在 python shell 中运行此代码而发生评估。

    在退货情况下,我想说最好的做法是仅使用 tryexcept

    def myfunc(x):
        try:
            return x / 0
    
        except:
            return x
    
    a = myfunc(20)
    print(a)
    

    【讨论】:

      猜你喜欢
      • 2013-04-09
      • 1970-01-01
      • 2014-02-28
      • 2013-11-22
      • 1970-01-01
      • 1970-01-01
      • 2015-06-14
      • 1970-01-01
      • 2015-02-16
      相关资源
      最近更新 更多