嵌套函数访问外部函数参数出现异常?求助原因解析
为什么修改后的装饰器会抛出UnboundLocalError?
这个问题其实是Python变量作用域规则在闭包里的典型表现,我来给你拆解清楚:
核心原因:Python的变量作用域判定规则
当你在函数内部对变量进行赋值时,Python会默认把这个变量标记为该函数的局部变量——不管外部作用域里有没有同名变量。这就是两段代码行为差异的关键。
第一段代码(正常运行)的逻辑
在第一段的wrapper函数里,你只是读取msg的值:
print(msg if msg is not None else "was none")
这里没有对msg做赋值操作,Python会按照LEGB作用域查找顺序(局部→闭包嵌套→全局→内置),向上找到msg_before函数参数传入的msg(属于闭包嵌套作用域),所以能正常读取到值,不会报错。
第二段代码(报错)的问题所在
修改后的wrapper函数里,你添加了赋值操作:
msg = msg if msg is not None else "was none"
这时候,Python看到你在wrapper内部对msg赋值,立刻把msg标记为wrapper的局部变量。当执行右边的msg if ...时,Python会优先查找局部作用域的msg,但此时这个局部变量还没被赋值,自然就抛出了UnboundLocalError: local variable 'msg' referenced before assignment。
简单说:你在给局部变量msg赋值之前,就试图引用它的值,程序当然会报错。
两种修复方法
方法1:用nonlocal声明作用域
告诉Python,msg不是wrapper的局部变量,而是来自外层嵌套作用域的变量:
def msg_before(msg=None): def actual_decorator(func): def wrapper(*args, **kwargs): nonlocal msg # 声明msg来自外层嵌套作用域 msg = msg if msg is not None else "was none" print(msg) result = func(*args, **kwargs) return result return wrapper return actual_decorator
方法2:换个变量名(更直观)
避免和外层的msg重名,这样就不会触发局部变量的标记:
def msg_before(msg=None): def actual_decorator(func): def wrapper(*args, **kwargs): display_msg = msg if msg is not None else "was none" # 用新变量名 print(display_msg) result = func(*args, **kwargs) return result return wrapper return actual_decorator
这两种方法都能解决你的问题,第二种甚至不需要改动作用域规则,理解起来更简单。
内容的提问来源于stack exchange,提问作者ruohola
相关产品推荐
相关产品推荐

