Python return和finally避坑

按一般的理解,函数中如果执行了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

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值