【问题标题】:Finally always runs just before the return in try block, then why update in finally block not affect value of variable returned by try block?finally 总是在 try 块返回之前运行,那么为什么 finally 块中的更新不会影响 try 块返回的变量的值呢?
【发布时间】:2020-07-01 14:09:27
【问题描述】:

finally 块在 try 块中的 return 语句之前运行,如下例所示 - 返回 False 而不是 True

>>> def bool_return():
...  try:
...    return True
...  finally:
...    return False
...
>>> bool_return()
False

同样,以下代码返回在 finally 块中设置的值:

>>> def num_return():
...  try:
...    x=100
...    return x
...  finally:
...    x=90
...    return x
...
>>> num_return()
90

但是,对于finally块中没有return语句的变量赋值,为什么finally块更新的变量值没有被try块返回? finally 块中的变量是否在 finally 块中的本地范围内?还是 try 块的返回值保存在内存缓冲区中并且不受 finally 块中的赋值影响? 在下面的示例中,为什么输出是 100 而不是 90?

>>> def num_return():
...  try:
...    x=100
...    return x
...  finally:
...    x=90
...
>>> num_return()
100

类似下面的例子:

In [1]: def num_return():
   ...:   try:
   ...:     x=[100]
   ...:     return x
   ...:   finally:
   ...:     x[0] = 90
   ...:

In [2]: num_return()
Out[2]: [90]

In [3]: def num_return():
   ...:   try:
   ...:     x=[100]
   ...:     return x[0]
   ...:   finally:
   ...:     x[0] = 90
   ...:

In [4]: num_return()
Out[4]: 100

【问题讨论】:

  • 最终块总是执行 参考:stackoverflow.com/questions/19805654/….
  • finally 子句在return 之后执行 - 在之前的任何时候它都不知道它应该执行。将return print("returning") 放入try 块中,您将看到print 的输出。如果它碰巧自己做了一个return,它只会替换原始返回值。

标签: python python-3.x


【解决方案1】:

帮助确认其他人已回答的小实验是将x 替换为单值列表,如下所示:

def num_return():
  try:
    x=[100]
    return x
  finally:
    x[0] = 90

现在返回的值是[90],所以在finally块中确实修改了列表。

但是如果你返回x[0],你会得到100(尽管我们只是基于列表本身在finally块中发生变化的事实)。


In [1]: def num_return():
   ...:   try:
   ...:     x=[100]
   ...:     return x
   ...:   finally:
   ...:     x[0] = 90
   ...:

In [2]: num_return()
Out[2]: [90]

In [3]: def num_return():
   ...:   try:
   ...:     x=[100]
   ...:     return x[0]
   ...:   finally:
   ...:     x[0] = 90
   ...:

In [4]: num_return()
Out[4]: 100

【讨论】:

  • 请你告诉我这个概念到底叫什么?
  • @variable 我会说它与 Python 的数据模型有关,即:变量是引用,整数是不可变的,但列表是可变的。 docs.python.org/3/reference/datamodel.html
【解决方案2】:

当您说return x 时,Python 将变量x 保存在该点 作为返回值。稍后更新 x 不会影响这一点。

【讨论】:

    【解决方案3】:

    以下子句摘自:https://docs.python.org/3/tutorial/errors.html(第 8.6 节)

    如果 try 语句到达 break、continue 或 return 语句,finally 子句将在 breakcontinuereturn 语句执行之前执行。

    在您的第一个示例中,return False 在 return True 之后执行,因此是结果。这也解释了第二个例子。

    对于最后一个,您的 return x 将 x 的值保存在代码的该点,更改变量 x 的值不会更改 return 语句的值。

    【讨论】:

    • 看来这个文档并不真实且具有误导性。正如return_stmt ::= "return" [expression_list]expression_listfinally 块执行之前被评估。不应该是the finally clause will execute just prior to the break, continue or return statement’s execution.,而是the finally clause will execute just =>in the middle<= of the break, continue or return statement’s execution.
    【解决方案4】:

    我认为您遇到的问题与价值分配有关,而不是 tryfinally 所做的。我建议阅读Facts and myths about Python names and values

    当你返回一个值时,它就像给一个变量赋值一样,例如result,而finally总是执行重新赋值。然后,您的示例代码可能表示为:

    # try 
    result = True # return
    # finally 
    result = False # return (reassign value)
    print(result) # Output: False
    
    # try
    x = 100 
    result = x # return
    # finally
    x = 90 
    result = x # return (reassign value)
    print(result) # Output: 90
    
    # try
    x = 100
    result = x # return
    # finally
    x = 90 # no return so result not updated
    print(result) # Output: 100
    print(x) # Output: 90 (x is changed actually)
    
    # try
    x = [100]
    result = x # return the list (result refer to a list and list is mutable)
    # finally
    x[0] = 90 # changing the list in-place so it affects the result
    print(result) # Output: [90]
    
    # try
    x = [100]
    result = x[0] # return the integer (result refer to the integer)
    # finally
    # changing the list in-place which have no effect to result unless reassign value by return x[0]
    x[0] = 90
    print(result) # Output: 100
    print(x) # Output: [90] (x is changed actually)
    

    【讨论】:

      【解决方案5】:

      所以 尝试是“试试这个代码” finally 是“如果一切顺利,那么最终执行此操作”

      【讨论】:

      • 这并不能解释所描述的行为
      猜你喜欢
      • 1970-01-01
      • 2017-07-20
      • 2017-09-20
      • 1970-01-01
      • 1970-01-01
      • 2013-04-08
      • 1970-01-01
      • 2012-05-02
      相关资源
      最近更新 更多