Python 3.x中的nonlocal及其在2.x中的变通办法
http://cndenis.github.io
2012-12-26
在Python 2.x中,函数内部可以定义函数,内层的函数可以读取外层函数的局部变量,但却不可以修改它.
def outter():
x = 1
def inner():
print("inner is called, x=", x)
return inner
outter()()
上面这个程序是没问题的,但是,下面这个就会出错:
def outter():
x = 1
def inner():
print("inner is called, x=", x)
x = 2
return inner
outter()()
提示竟然是UnboundLocalError: local variable 'x' referenced before assignment
,找不到变量。
这个错误在Python 3.x中的解决方法是使用Py3k新增的关键词nonlocal
:
def outter():
x = 1
def inner():
nonlocal x
print("inner is called, x=", x)
x = 2
return inner
outter()()
但Python 2.x中没有这个关键词,怎么办呢?如果对变量的改变的不需要影响外层的话,可以新建一个变量来用也可以。
新建变量的方式:
def outter():
x = 1
def inner():
y = x
print("inner is called, x=", y)
y = 2
return inner
outter()()
由于y是在内层函数中定义的,可以随便改变,但外层函数看不见y。而如果需要内层对变量的改变被外层看到的话,变通的方法是使用可变的对象,例如dict、对像的属性等。例如 Python 3.x中的代码:
def outter():
x = 1
def inner():
nonlocal x
print("inner is called, x=", x)
x = 2
inner()
print("outter after inner called, x=", x)
outter()
#Python 3.3中输出:
#inner is called, x= 1
#outter after inner called, x= 2
在Python 2.x中用dict的方式变通为:
def outter():
x = {}
x[0] = 1
def inner():
print("inner is called, x=", x[0])
x[0] = 2
inner()
print("outter after inner called, x=", x[0])
outter()
#Python 2.7中输出:
#inner is called, x= 1
#outter after inner called, x= 2
用对像的属性的方式:
class C(object):
pass
def outter():
x = C()
x.v = 1
def inner():
print("inner is called, x=", x.v)
x.v = 2
inner()
print("outter after inner called, x=", x.v)
outter()
#Python 2.7中输出:
#inner is called, x= 1
#outter after inner called, x= 2
以上内容参考了:Python的闭包与nonlocal 以及 Simulating nonlocal in Python 2.x
blog comments powered by Disqus