by cnDenis http://cndenis.iteye.com 2012年12月26日
在Python 2.x中,函数内部可以定义函数,内层的函数可以读取外层函数的局部变量,但却不可以修改它.
1 2 3 4 5 6 7 8 |
#!/usr/bin/python def outter(): x = 1 def inner(): print("inner is called, x=", x) return inner outter()() |
上面这个程序是没问题的,但是,下面这个就会出错:
1 2 3 4 5 6 7 8 9 |
#!/usr/bin/python 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
:
1 2 3 4 5 6 7 8 9 10 |
#!/usr/bin/python def outter(): x = 1 def inner(): nonlocal x print("inner is called, x=", x) x = 2 return inner outter()() |
但Python 2.x中没有这个关键词,怎么办呢?如果对变量的改变的不需要影响外层的话,可以新建一个变量来用也可以。
新建变量的方式:
1 2 3 4 5 6 7 8 9 10 |
#!/usr/bin/python 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中的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/usr/bin/python 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的方式变通为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/python 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 |
用对像的属性的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/usr/bin/python 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