关于python:在函数外声明的变量

variables declared outside function

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
referenced before assignment error in python
local var referenced before assignment

好吧,我只是想看看变量范围是如何工作的,并且在下面的情况下运行的。全部从终端运行:

1
2
3
4
5
6
7
8
9
  x = 1
  def inc():
      x += 5

  inc()
  Traceback (most recent call last):
    File"<stdin>", line 1, in <module>
    File"<stdin>", line 2, in inc
  UnboundLocalError: local variable 'x' referenced before assignment

所以我想也许我在我的方法中无法访问x,所以我尝试:

1
2
3
4
 def inc():
    print x

 1

这是有效的。现在我知道我可以做:

1
2
3
 def inc():
     global x
     x += 1

这样就行了。但我的问题是为什么第一个例子失败了。我的意思是,由于print x工作,x在函数内部是可见的,那么为什么x+=5会失败呢?


与使用"真"词汇范围的语言不同,python选择为变量设置特定的"名称空间",无论是globalnonlocal还是local。可以说,让开发人员有意识地在头脑中使用这样的名称空间进行编码更为明确,因此更易于理解。我认为这样的复杂性会使语言更加笨拙,但我想这都取决于个人喜好。

以下是有关global的一些例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>> global_var = 5
>>> def fn():
...     print(global_var)
...
>>> fn()
5
>>> def fn_2():
...     global_var += 2
...     print(global_var)
...
>>> fn_2()
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
  File"<stdin>", line 2, in fn_2
UnboundLocalError: local variable 'global_var' referenced before assignment
>>> def fn_3():
...     global global_var
...     global_var += 2
...     print(global_var)
...
>>> fn_3()
7

同样的模式也可以应用于nonlocal变量,但是这个关键字只对后一个Python版本可用。

如果您想知道,nonlocal用于变量不是全局变量,但不在所使用的函数定义中。例如,def中的def是一种常见现象,部分原因是缺乏多语句lambda。在早期的Python身上,有一种方法可以绕过这个功能的缺失,不过,我隐约记得它涉及到使用一个元素列表…

注意,写入变量是需要这些关键字的地方。仅仅从他们那里阅读并不含糊,因此不需要。除非你有内部的def使用与外部的相同的变量名,这只是应该避免诚实。


当python解析一个函数时,它会注意到什么时候进行了变量赋值。当存在赋值时,默认情况下,它假定该变量是局部变量。要声明赋值引用全局变量,必须使用global声明。

当访问函数中的变量时,将使用legb作用域规则查找其值。

所以,第一个例子

1
2
3
4
  x = 1
  def inc():
      x += 5
  inc()

生成UnboundLocalError,因为python将inc中的x确定为局部变量,

访问x时,在第二个示例中有效

1
2
 def inc():
    print x

因为在这里,按照legb规则,python在本地范围内查找x,没有找到,然后在扩展范围内查找,仍然没有找到,最后在全局范围内成功查找。


函数的本地名称在定义函数时确定:

1
2
3
4
5
6
>>> x = 1
>>> def inc():
...     x += 5
...    
>>> inc.__code__.co_varnames
('x',)

在这种情况下,x存在于本地命名空间中。执行x += 5需要x的一个预先存在的值(对于整数,它与x = x + 5类似),并且在函数调用时失败,因为本地名称是未绑定的——这正是为什么将异常UnboundLocalError命名为这样。

比较另一个版本,其中x不是局部变量,因此它可以在全局范围内解决:

1
2
3
4
5
>>> def incg():
...    print(x)
...    
>>> incg.__code__.co_varnames
()

常见问题解答中的类似问题:http://docs.python.org/faq/programming.html why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value