Python嵌套函数:为何一个内函数正常另一个报变量未绑定错误
报错核心原因:Python的静态作用域判定规则
Python在函数定义阶段就会确定函数内所有变量的作用域归属,判定规则非常直接:
- 如果函数内只读取某个变量、从来不对它做赋值操作,Python会逐层从外层作用域(闭包外层、全局、内置作用域)找这个变量的值
- 只要函数内任意位置存在对某个变量的赋值操作(不管赋值语句在分支、循环这类不一定会执行的代码块里),Python就会把这个变量标记为当前函数的局部变量,不会再去外层作用域查找。
两个版本表现差异的具体解释
可正常运行的第一个版本
第一个say函数内部,从来没有对running_high、last_score、who这几个来自外层announce_highest函数的参数做赋值操作,仅读取这些变量的值参与计算。因此Python会将这几个变量识别为闭包外层变量,直接从外层作用域读取值,不会出现作用域冲突。
抛出错误的第二个版本
第二个say函数内部多了一行赋值语句:running_high = scores[who]-last_score。
这行代码直接导致Python在定义say函数时,就把running_high标记为say的局部变量。但执行到判断条件if gain > running_high时,这个局部变量还没有被赋值(赋值逻辑在if分支内部,还没走到),尝试读取未赋值的局部变量就会抛出题目里的错误。
补充:很多人会误以为赋值在if分支里,没走到分支就不会影响变量判定,这个认知是错的。Python的作用域判定是函数加载时就完成的,和代码运行时走不走到某条分支没有关系。如果确实需要在嵌套函数里修改外层闭包变量,需要显式用
nonlocal关键字声明变量来自外层作用域,比如:def say(*scores): nonlocal running_high # 显式声明running_high来自外层闭包,不是局部变量 gain = scores[who] - last_score if gain > running_high: running_high = scores[who]-last_score print(gain,"point(s)! That's the biggest gain yet for Player",who) return announce_highest(who, scores[who], gain) return announce_highest(who,scores[who],running_high)
内容的提问来源于stack exchange,提问作者Azerukit
相关产品推荐
相关产品推荐

