按一般的理解,函数中如果执行了return语句,那么函数的执行就完成了。比如传入一个正数,那么第一个判断成立后就立即返回,后面的判断不再执行。
def func(n):
if n > 0:
return '正数'
elif n < 0:
return '负数'
else:
return '零'
上述结论即使遇到yield也成立
def func(n):
return n**2
yield 2
res = func(10)
# 因为无法运行到yield 2,所以会报错
print(next(res))
# 输出:StopIteration: 100
直到遇到finally
def func():
try:
print("try")
raise KeyError
except KeyError:
print("except")
return 1
finally:
print("finally")
return 2
if __name__ == "__main__":
result = func()
print(result)
# 输出:try
# except
# finally
# 2
通过上面的例子可以看到,except下面的语句是执行了的,也就是说return 1执行了。但是,打印的result不仅不是返回的1,finally后面的代码还继续执行了。
我们尝试输出上述代码的字节码,查看python代码编译结果可以使用dis模块。
def func():
try:
print("try")
raise KeyError
except KeyError:
print("except")
return 1
finally:
print("finally")
return 2
if __name__ == "__main__":
import dis
print(dis.dis(func))
部分字节码如下:
dis.dis模块会输出格式化字节码信息,7列信息分别表示:
1:原代码所在行数
2:当前指令,用-->表示
3:带标签的指令,用>>表示
4:指令地址
5:指令名称
6:操作参数(这个数字不是其直接含义,应该是一个指针)
7:参数解释
我们重点关注下第一次执行的return语句,字节码44就是执行return 1,此时其后的代码应该结束,字节码46刚好是这个操作。但这个操作前有一个标签>>,因此,finally并没有被结束。即return并不是真正的立即返回,只是将返回值压入栈,当条件满足时才弹出返回。因此,这里执行了两次return,就是先后把1和2入栈,弹出的时候自然就是2
(有大神分析了C源码,感兴趣可以查看https://segmentfault.com/a/1190000010701665)