【问题标题】:Variables declared outside function [duplicate]在函数外部声明的变量[重复]
【发布时间】:2012-01-20 15:42:30
【问题描述】:

我只是想看看变量作用域是如何工作的,结果遇到了以下情况(都是从终端运行的):

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 会失败?

【问题讨论】:

  • 不到 24 小时前,有人问了very similar question,也许你想看看。
  • 每个人都把事情复杂化了,而忽略了使用global 的最重要的功能。也就是说,您可以在函数定义之后定义一个变量x,然后仍然使用global x 在该函数内部使用/访问它。
  • 在 Python 中,仅在函数内部引用的变量是隐式全局的。如果一个变量在函数体中的任何位置被赋值,除非明确声明为全局变量,否则它被假定为局部变量。有关详细信息,请参阅此链接:docs.python.org/faq/…

标签: python


【解决方案1】:

与使用“真实”词法作用域的语言不同,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。有一个 hack 可以绕过早期 Python 中缺少此功能,但我依稀记得它涉及使用单元素列表...

请注意,写入变量是需要这些关键字的地方。只是从他们那里阅读并不模棱两可,因此不需要。除非您的内部 defs 使用与外部变量名称相同的变量名,否则老实说应该避免。

【讨论】:

  • 在 Python 中,仅在函数内部引用的变量是隐式全局的。如果一个变量在函数体内的任何地方都被赋值,除非明确声明为全局变量,否则它被假定为局部变量。欲了解更多信息,请参阅此链接:docs.python.org/faq/…
【解决方案2】:

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

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


那么,第一个例子

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

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

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

def inc():
    print x

因为这里,按照LEGB规则,Python在本地范围内寻找x,没有找到,然后在扩展范围内寻找,依旧没有找到,最后在全局作用域成功。

【讨论】:

  • 在 Python 中,仅在函数内部引用的变量是隐式全局的。如果一个变量在函数体中的任何位置被赋值,除非明确声明为全局变量,否则它被假定为局部变量。欲了解更多信息,请参阅此链接:docs.python.org/faq/…
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 2023-04-03
    • 2018-11-10
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    相关资源
    最近更新 更多