Python自由变量.为什么这会失败?

Ele*_*naT 7 python variables binding function

以下代码打印123:

>>> a = 123
>>> def f():
...     print a
...
>>> f()
123
>>>
Run Code Online (Sandbox Code Playgroud)

但是以下失败了:

>>> a = 123
>>> def f():
...     print a
...     a = 456
...     print a
...
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
UnboundLocalError: local variable 'a' referenced before assignment
>>>
Run Code Online (Sandbox Code Playgroud)

我原以为这打印:

123
456
Run Code Online (Sandbox Code Playgroud)

我在这里错过了什么?

PS如果重要,我正在使用Python 2.6.6.

小智 8

如果函数只从变量读取,则假定它是全局的.如果函数永远写入它,则假定它是本地的.在你的第二个函数中,a被写入,因此它被认为是本地的.然后上面的行(它的读取位置)无效.

这是Python FAQ的链接:http://docs.python.org/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

  • Python已编译.它只是编译为字节码,在虚拟机上运行(即完全像Java) (2认同)

Gan*_*ndi 5

这是因为Python会自动将变量视为全局变量,除非您在函数中定义或尝试对其进行修改。尝试添加global a到您的代码中。

>>> a = 123
>>> def f():
...     global a
...     print a
...     a = 456
...     print a
... 
>>> f()
123
456
>>> a
456
Run Code Online (Sandbox Code Playgroud)

在第一个示例中,您没有定义也没有修改,因此它是全局的。但是,例如,如果您想将a加20,则还必须使用global a

另请注意,a in f函数是全局函数,其值在f函数运行后会有所不同。

如果要创建局部变量,请记住,该声明总是在读取之前进行,因此print a不能在之前进行a = 456

编辑:好的,当我们谈论闭包和使用global的危险时,还有另一种可能性。

>>> a = 123
>>> def f():
...     b = a
...     print b
...     b = 456
...     print b
... 
>>> f()
123
456
>>> a
123
>>> 
Run Code Online (Sandbox Code Playgroud)

在这里,我们使用闭包只读功能来制作的副本,然后修改该副本,而无需修改外部a变量AS LONG AS IT'S INTEGER。请记住,它b始终引用aa例如,如果为,并且f操作类似于b.append(3),则两者ab都将在范围之外可用并进行修改。

方法的选择因需要而异。


e-s*_*tis 5

您正在使用的是一个闭包:您从一个外部作用域获取一个变量并将其包含在一个功能块中.

你的代码完全没问题,可以在javascript中运行.

不幸的是,在Python中,闭包是只读的.

并且错误始终UnboundLocalError: local variable 'var_name' referenced before assignment是完全误导的错误.

简而言之,这不是你,这是一个语言限制加上错误的错误信息.

编辑:

我可以看到这里有几个人提倡使用global,这有危险的副作用:你可以访问具有相同名称的变量,在当前的几个范围之上,这不是你想要的闭包.

该解决方案已在Python 3中添加,其nonlocal关键字正是如此:从内部作用域中的外部作用域重新绑定变量.

有一种方法可以模拟python 2.x的nonlocal,但实际上你最好不要为你的变量赋值:复制值,返回值,只修改可变类型,你会没事的.