Python中如何使方法内声明的变量对内部函数可见
- 所属逻辑为代码生成器逻辑,存在一个结构不可修改的类,仅有权限修改该类下某一个指定方法的内容
- 该方法内包含变量声明、内部函数声明,需求为让方法内声明的变量可在内部函数中正常访问
方案1:在内部函数中使用
global关键字声明变量
对应代码:class SomeClassICannotModify(AbstractConditional): def __init__(self, a, b): ..... def method_which_content_I_can_modify(self): myvar = 1 def my_inner_func(): global myvar myvar = 1 return myvar print(my_inner_func())触发报错:
NameError: name 'myvar' is not defined
问题原因:global关键字仅指向模块层级声明的全局变量,无法识别方法内部声明的局部作用域变量。方案2:去掉
global关键字,直接在内部函数中操作myvar
对应代码:def method_which_content_I_can_modify(self): myvar = 1 def my_inner_func(): myvar = 1 return myvar触发报错:
UnboundLocalError: local variable 'cond' referenced before assignment(注:代码生成逻辑会追加额外内容,此处cond可等价替换为myvar理解,本质是局部变量在赋值前被引用的错误)
问题原因:Python默认会将函数内首次赋值的变量识别为函数自身的局部变量,不会自动向外层嵌套作用域查找同名变量,最终触发赋值前引用的错误。方案3:将
myvar作为内部函数的默认参数传入
对应代码:def method_which_content_I_can_modify(self): myvar = 1 def my_inner_func(v = myvar): v = 1 return v触发报错:与方案2一致的
UnboundLocalError
问题原因:默认参数仅在函数定义时绑定变量的初始值,无法解决代码生成追加内容导致的作用域识别问题。
标准写法(适配绝大多数场景)
使用nonlocal关键字在内部函数中声明需要访问的外层方法变量,该关键字是Python专门为嵌套函数场景设计的,用于引用外层非全局作用域的变量。
示例代码:
class SomeClassICannotModify(AbstractConditional): def __init__(self, a, b): ..... def method_which_content_I_can_modify(self): myvar = 1 def my_inner_func(): nonlocal myvar # 声明当前myvar引用自外层方法作用域 # 代码生成器追加的任意myvar读写操作均可正常执行 myvar = 2 return myvar print(my_inner_func())
nonlocal声明会直接告知Python解释器,该变量不属于内部函数的局部作用域,需要向外层嵌套的方法作用域查找对应变量,既不会出现global的作用域层级匹配错误,也不会触发局部变量赋值前引用的问题。
兼容写法(适配代码生成逻辑的极端场景)
如果代码生成器会自动在内部函数中插入同名变量赋值、破坏nonlocal声明逻辑,可以用可变容器包装外层变量,绕开Python的作用域赋值限制。
示例代码:
def method_which_content_I_can_modify(self): # 用可变列表作为变量容器存储myvar,初始值为1 myvar_holder = [1] def my_inner_func(): # 无需额外做作用域声明,仅读取容器变量、修改容器内部存储的值不会被识别为局部变量 myvar_holder[0] = 2 return myvar_holder[0]
该方案的原理是:内部函数仅对myvar_holder做读取操作(没有对myvar_holder本身重新赋值),不会被Python标记为局部变量;通过修改可变对象内部存储的内容,即可实现对外层变量值的读写,兼容性更强,不会被代码生成器的追加内容轻易破坏。
内容的提问来源于stack exchange,提问作者lalebarde

