scoping error in recursive closure
为什么这样做:
1 2 3 4 5 | def function1(): a = 10 def function2(): print a function2() |
但这并不是:
1 2 3 4 5 6 7 8 | def function1(): a = 10 def function2(): print a a -= 1 if a>0: function2() function2() |
我得到这个错误:
1 | UnboundLocalError: local variable 'a' referenced before assignment |
这个错误似乎并不能很好地描述根本问题。Mike解释了这些信息,但这并不能解释根本原因。
实际的问题是,在python中,不能给封闭变量赋值。因此在函数2中,"a"是只读的。当你给它赋值时,你会创建一个新的变量,正如迈克指出的那样,你在写之前就已经读过了。
如果要从内部范围将赋值给外部变量,则必须这样做:
1 2 3 4 5 6 7 8 | def function1(): al = [10] def function2(): print al[0] al[0] -= 1 if al[0]>0: function2() function2() |
因此,al是不变的,但它的内容不是,您可以在不创建新变量的情况下更改它们。
应该注意,这是Python中的语法错误。python本身(在字节码级别)可以很好地分配给这些变量;2.x中没有语法来表示您想要这样做。它假定,如果在嵌套级别中为变量赋值,则意味着它是局部变量。
这是一个巨大的缺点;能够分配给闭包是最基本的。我已经和查理的黑客解决过几次了。
python 3用非常笨拙的"nonlocal"关键字修复了这个问题:
1 2 3 4 5 6 7 8 9 10 | def function1(): a = 10 def function2(): nonlocal a print(a) a -= 1 if a>0: function2() function2() function1() |
这种语法只在3.x中可用是非常糟糕的;大多数人都困在2.x中,必须继续使用黑客来解决这个问题。这非常需要反向移植到2.x。
http://www.python.org/dev/peps/pep-3104/
在非工作代码段中,当您说"
注意,这完全不依赖于递归性或使用闭包。考虑这个函数的例子
1 2 3 | def foo(): print a a = 4 |
打电话给它也会给你一个
如果我在设计这个函数,我可能会使用一种更像
1 2 3 4 5 6 7 8 | def function1(): a = 10 def function2(a=a): print a a -= 1 if a > 0: function2(a) function2() |
(当然也可以是