在Mark Lutz的“学习Python”中,我读到: “函数可以自由地使用在语法封闭函数和全局范围中分配的名称,但是它们必须声明这样的非局部和全局变量才能更改它们” 我没能在Python 2.7中测试它们
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
'global'(NameError:全局名称'f1_a'未定义)和'nonlocal'(非本地f1_a,SyntaxError:无效语法)不起作用。这是否意味着没有办法改变外部函数中引入的变量从内部(直接封闭)引入?
答案 0 :(得分:2)
要让您的代码正常工作,您需要nonlocal
关键字,但这只存在于Python 3中。如果您使用的是Python 2,那么您需要使用一些而是一种解决方法。
一个选项是将外部函数中的值放在可变容器(例如列表)中。内部函数可以将容器变异,即使它不能重新绑定变量:
def f1():
f1_a = ['f1_a'] # add a list around the value
def f2():
f2_a = 'f2_a'
print 'f2_a={:s}'.format(f2_a)
print 'f1_a={:s}'.format(f1_a[0]) # read the value from inside the list!
f1_a[0] = 'f1f2_a' # mutate the list in place
f2()
print 'f1_a={:s}'.format(f1_a[0]) # read from the list here too
虽然上面的代码确实有效,但我强烈建议您升级到Python 3,除非绝对需要保留Python 2以实现向后兼容,或者因为依赖关系不是这些天依赖情况要好得多,因为几乎每个实际维护的项目都已移植到Python 3中,所以如果您使用的是未移植过的东西,那么它就会被移植到Python 3中。可能没有得到任何错误修复。几乎所有新代码都应该专门针对Python 3。
答案 1 :(得分:1)
def f1():
f1_a = 'f1_a'
def f2():
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()
这将适用于python 3或更高版本,因为nonlocal
只能用于python 3或后者
python 2你可以通过这种方式存档
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
使用空类
class emptyClass: pass
def f1():
emp = emptyClass()
emptyClass.f1_a = 'f1_a'
def f2():
f2_a = 'f2_a'
print('f2_a={:s}'.format(f2_a))
print('f1_a={:s}'.format(emptyClass.f1_a))
emptyClass.f1_a = 'f1f2_a'
f2()
print('f1_a={:s}'.format(emptyClass.f1_a))
f1()
答案 2 :(得分:1)
Blcknght回答提供了一种实现你想要的方法,但是我想强调你的异常发生是因为你在f2函数中重新绑定 f1_a变量(在f1中定义)。
您可以从附带的函数中访问外部函数变量。
如果在内部函数中删除f1_a的新绑定,则代码在python 2.7中工作:
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)
# f1_a = 'f1f2_a'
print 'f1_a={:s}'.format(f1_a)
f2()
>>> f1()
f1_a=f1_a
f2_a=f2_a
f1_a=f1_a
此代码段显示
一旦将f1_a重新绑定到另一个对象
,您的代码就会中断
因此,关于您的原始问题 - 您可以从内部函数访问外部函数属性。您还可以改变容器内的值。但重新绑定不可变变量会导致您的问题。