Python札记7:在try...except...finally中return

你应该对try...except...finally的用法熟悉:

try:
    pass
except:
    pass
finally:
    pass

不论try语句块中发生了什么异常,finally语句块中的代码都会被执行。所以我们通常在finally语句块中做清理工作,例如关闭文件等等。

请看下面的代码,输出是什么呢?

def f():
  try:
    return 1
  finally:
    print("hehe")

print(f())

finally块中的代码必定执行,所以输出如下:

hehe
1

也就是说,虽然try中有return语句,但是退出try...finally块之前,也一定会执行finally块中的语句。

接着,你可能会尝试这样做:

def f():
  try:
    return 1
  finally:
    print("hehe")
    return 2

print(f())

输出:

hehe
2

可以看出,虽然try中返回的是1,但是因为返回之前执行了finally块中的语句,所以返回值被更新成了2。过程如下:

全局
函数f
try
return确定返回值为1
finally
return更新返回值为2

下面来尝试一个更加奇怪的:

def f():
  i = 1
  try:
    i = 2
    return i
  finally:
    i = 12
    print("value of i: %d" % i)
    
print(f())

输出:

value of i: 12
2

因为输出了“value of i: 12”,那么finally块肯定是被执行了的。而且i的值在finally块中也被修改为了12。但是函数f的返回值为仍然为try块中返回的2。

原因是在执行return语句时,Python会将当前的返回值放到函数调用栈顶,在函数返回后弹出。所以,虽然finally中修改了i的值,但是并没有修改函数调用栈顶部的返回值,除非再在finally块中执行一个return语句来覆盖栈顶的返回值。过程如下:

全局
函数f
try
return确定返回值为2
finally

原来是这样。那你可能又会尝试下面的代码:

def f():
  i = 1
  try:
    i = 2
    return i
    return i + 1 # 这里会执行吗?
  finally:
    i = 12
    print("value of i: %d" % i)

print(f())

你在return i下面加了一行return i + 1,想试着更改返回值?不要被finally搞糊涂了,return就是return,只要执行了return,那就标志结束当前函数,将控制权交给调用者,而后面的代码是一定不会执行了。但是finally又是如此特殊,它允许我们在退出try...finally...块之前执行额外的代码,上面代码的执行过程如下:

全局
函数f
try
return确定返回值为2
finally

另外,我们把except加上会是什么样的呢:

def f():
  try:
    return 1
    raise ValueError() # 不会执行
  except ValueError:
    return 2
  finally:
    print("hehe")

print(f())

上面的raise根本不会执行,所以输出你应该能猜得到:

hehe
1

raise放到return 1前面:

def f():
  try:
    raise ValueError()
    return 1
  except ValueError:
    return 2
  finally:
    print("hehe")

print(f())

输出:

hehe
2

因为抛出了异常,所以return 1也不会执行了,直接进入except块中。因为finally必定执行,所以下面代码的输出,不用说你也知道:

def f():
  try:
    raise ValueError()
    return 1
  except ValueError:
    return 2
  finally:
    print("hehe")
    return 3

print(f())

总结

两点:

  • try和except中return语句设定的返回值,可以在finally块中被修改;
  • 实践中不要在finally中使用return,这是一种不好的代码,容易让人产生疑惑。finally块主要用于进行清理工作。

我的知乎:奔三的鑫鑫

欢迎关注微信公众号:小鑫的代码日常

欢迎加入Python学习交流群:532232743,这里有各路高手等着你~

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页