Python中try放在函数定义前与函数内部的差异及执行顺序问题
两种写法的异常捕获范围本质差异
外层try包裹函数定义的执行流程
- 代码逐行运行时,程序首先进入第一层try块的保护区间
- 遇到
def chiz(...)语句时,Python做的事只是当场创建一个函数对象:把函数内部的代码块编译成可执行字节码,和函数名绑定到一起,全程根本不会运行return dict[key]这行取字典值的逻辑 - 这个阶段外层try能捕获的,只有写函数定义本身时当场触发的错误:比如def行漏了冒号、缩进错位、写了非法参数名这类——只要函数定义本身的语法是对的,这个创建函数的过程就不会抛出任何异常
- 等函数对象创建完成,外层try块的代码就执行完了,对应的异常保护范围直接失效
- 后续程序跳出try块,依次创建user_01字典、调用chiz函数,直到这个时候才真正跑到之前存在函数对象里的取键代码,触发的KeyError早就不在外层try的包裹范围内,自然会抛出未捕获的栈跟踪报错。
内部try放在函数体中的执行流程
- 同样先通过def语句创建chiz函数对象,这个创建过程和上面完全一致
- 函数定义完成后,程序依次执行字典创建、chiz函数调用的逻辑
- 真正进入函数体运行时,才会进入函数内部自带的try块保护范围:当
return dict[key]触发KeyError时,异常正好处在try的捕获区间内,会被对应的except分支接住,执行打印逻辑。
容易踩的认知误区
不少人觉得把def包在try里,就能给这个函数后续所有调用加一层永久的异常保护,本质是把两个完全独立的执行过程搞混了:
- 定义阶段:运行def语句创建函数对象的过程
- 执行阶段:后续代码调用函数、真正运行内部逻辑的过程
Python的def是即时生效的执行语句,不是给函数套永久结界的标记——它的作用只在def语句运行的那一瞬间生效,等函数定义完成,外层try的保护也就跟着结束了。如果确实想在函数调用时捕获这类异常,只需要把chiz(user_01, "weight")这行调用代码也挪到最外层的try块里,这个时候异常才会处于try的捕获范围中。
内容的提问来源于stack exchange,提问作者armin
相关产品推荐
相关产品推荐

