在函数外声明的变量

时间:2012-01-20 15:42:30

标签: python

  

可能重复:
  referenced before assignment error in python
  local var referenced before assignment

好的,我只是试着看一下变量范围如何工作并在以下情况下运行。全部从终端跑出来:

  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,所以我尝试了:

 def inc():
    print x

 1

所以这很有效。现在我知道我可以这样做:

 def inc():
     global x
     x += 1

这会奏效。但我的问题是为什么第一个例子失败了。我的意思是我希望自print x起作用,x在函数内部可见,那么为什么x + = 5会失败?

3 个答案:

答案 0 :(得分:35)

与采用“真正的”词法范围的语言不同,Python选择为变量设置特定的“命名空间”,无论是globalnonlocal还是本地。可以说,让开发人员有意识地编写这样的命名空间代码更加明确,因此更容易理解。我认为这种复杂性会使语言变得更加笨拙,但我想这完全取决于个人偏好。

以下是有关global的一些示例: -

>>> 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。虽然在早期的Pythons中有一个黑客可以绕过这个功能的缺乏,我依旧记得它涉及使用单个元素列表......

请注意,写入变量是需要这些关键字的地方。只是阅读它们并不含糊,因此不需要。除非内部def使用与外部变量名称相同的变量名称,否则应该避免诚实。

答案 1 :(得分:20)

当Python解析函数时,它会记录变量赋值的时间。当存在赋值时,它默认假定该变量是局部变量。要声明赋值引用全局变量,必须使用global声明。

当您访问函数中的变量时,会使用LEGB scoping rules查找其值。


所以,第一个例子

  x = 1
  def inc():
      x += 5
  inc()

产生UnboundLocalError,因为Python确定x内的inc为局部变量,

访问x时可以使用第二个示例

 def inc():
    print x

因为在这里,根据LEGB规则,Python在本地范围内查找x,找不到它,然后在扩展范围内查找它,仍然找不到它,最后查找它在全球范围内成功。

答案 2 :(得分:7)

当函数定义时,决定函数的本地名称:

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

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

比较其他版本,其中x不是本地变量,因此可以在全局范围内解析:

>>> 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