【发布时间】:2019-01-18 15:27:58
【问题描述】:
尽管在全局范围内声明了变量,但我收到了 UnboundLocalError。似乎该变量被假定/强制为该特定语句的局部变量。
我不明白为什么 if 语句条件中的变量会被区别对待。有人可以解释发生了什么吗?
以下 sn-p 是我尝试做的一个简化示例:
In [1]: global mock
... mock = False
...
...
... def foo():
... if not mock:
... # do stuff
... mock = True
...
... # do other stuff
...
...
... foo()
这会引发 UnboundLocalError,尽管在函数声明的正上方声明了全局 bool。
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-31-540737067cb1> in <module>()
7
8
----> 9 foo()
<ipython-input-31-540737067cb1> in foo()
3
4 def foo():
----> 5 if not mock:
6 mock = True
7
UnboundLocalError: local variable 'mock' referenced before assignment
但是,这个 sn-p 按预期运行:
In [2]: mock = False
...
...
... def bar():
... return mock
...
...
... bar()
Out[2]: False
同样,这个在 if 语句体中带有变量的 sn-p 也可以按预期运行:
In [3]: mock = False
...
...
... def foobar():
... if True:
... return mock
...
... return True
...
...
... foobar()
Out[3]: False
我在文档 (https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces) 中找到了以下关于范围和命名空间的文章,但我认为它应该根据以下内容按预期工作,
虽然范围是静态确定的,但它们是动态使用的。在执行过程中的任何时候,至少有三个嵌套作用域的命名空间是可以直接访问的:
- 最里面的范围,首先搜索,包含本地名称
- 从最近的封闭范围开始搜索的任何封闭函数的范围都包含非本地名称,但也包含非全局名称
- 倒数第二个作用域包含当前模块的全局名称
- 最外层范围(最后搜索)是包含内置名称的命名空间
我在 Windows 10 上的 Conda 中使用 Jupyter 4.4.0 和 Python 3.6.6 和 IPython 6.5.0,但我能够使用控制台 IPython 和运行 Python 3.6.0 的 IDLE 3.6.0 GUI 重现此行为。
编辑:不知何故,以下 sn-p 不受影响?似乎这与更新同一变量中的变量有关。我觉得我现在一定错过了一些微不足道的事情。
In [4]: global mock # also works without this line
... mock = False
...
...
... def foo1():
... if not mock:
... return mock
...
... return True
...
...
... foo1()
Out[4]: False
【问题讨论】:
标签: python python-3.x scope