如何修改外层函数变量?Python2.7测试Mark Lutz内容遇报错
解决Python 2.7嵌套函数中的UnboundLocalError问题
Mark Lutz在《Learning Python》中提到:“函数可自由使用语法嵌套函数及全局作用域中定义的名称,但修改这些非局部和全局名称必须进行声明”。
你在Python 2.7里碰到的这个UnboundLocalError,其实是Python作用域规则在“搞事情”,咱们一步步拆解清楚:
先看你的报错代码:
def f1(): f1_a = 'f1_a' def f2(): # global f1_a # nonlocal f1_a f2_a = 'f2_a' print 'f2_a={:s}'.format(f2_a) print 'f1_a={:s}'.format(f1_a) f1_a = 'f1f2_a' f2() print 'f1_a={:s}'.format(f1_a) >>> f1() # 报错:UnboundLocalError: local variable 'f1_a' referenced before assignment
为啥会报错?
Python的变量查找逻辑很直接:只要你在函数内部给某个变量赋值,Python就会默认这个变量是该函数的局部变量——哪怕外部嵌套作用域里有同名变量。在你的f2函数里,后面有f1_a = 'f1f2_a'这行赋值代码,所以Python直接把f1_a认定为f2的局部变量。但你在赋值之前先尝试print f1_a,这时候局部的f1_a还没被定义,自然就抛出“引用前未绑定”的错误了。
另外要提一句:nonlocal关键字是Python 3才引入的语法,Python 2.7根本不支持,所以你注释掉的那行就算解开也会报语法错误;而global是用来声明全局变量的,这里的f1_a是f1函数的局部变量,不是全局的,所以global也解决不了问题。
Python 2.7里的解决办法
既然Python 2没有nonlocal,咱们可以用两个变通方案绕开这个限制:
方案1:用可变对象包裹变量
把f1_a放到列表(或字典)里,因为列表是可变对象,修改它的元素不需要声明作用域:
def f1(): f1_a = ['f1_a'] # 用列表包裹变量 def f2(): f2_a = 'f2_a' print 'f2_a={:s}'.format(f2_a) print 'f1_a={:s}'.format(f1_a[0]) f1_a[0] = 'f1f2_a' # 修改列表元素 f2() print 'f1_a={:s}'.format(f1_a[0]) >>> f1() # 输出: # f2_a=f2_a # f1_a=f1_a # f1_a=f1f2_a
方案2:使用函数属性
把f1_a作为f1函数的属性存储,这样在f2里可以直接访问并修改:
def f1(): f1.f1_a = 'f1_a' # 定义为函数属性 def f2(): f2_a = 'f2_a' print 'f2_a={:s}'.format(f2_a) print 'f1_a={:s}'.format(f1.f1_a) f1.f1_a = 'f1f2_a' # 修改函数属性 f2() print 'f1_a={:s}'.format(f1.f1_a) >>> f1() # 输出: # f2_a=f2_a # f1_a=f1_a # f1_a=f1f2_a
这两个方案都能实现你修改嵌套作用域变量的需求,完美适配Python 2.7的环境。
内容的提问来源于stack exchange,提问作者Vladimir Zolotykh
相关产品推荐
相关产品推荐

