在Python参考手册此陈述的Resolution of Names部分:
[..]如果当前范围是一个函数范围和名称是指一个局部变量还没有被势必会在其中所使用的名称的点值,一个UnboundLocalError
引发异常[..]
这时候UnboundLocalError
发生在官方消息。如果您在CPython的字节码与dis
生成的功能f
看看你可以看到它试图从局部范围加载名称时,其价值甚至还没有尚未设置:
>>> dis.dis(f)
3 0 LOAD_GLOBAL 0 (print)
3 LOAD_CONST 1 (1)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
4 10 LOAD_GLOBAL 0 (print)
13 LOAD_FAST 0 (a) # <-- this command
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
19 POP_TOP
5 20 LOAD_CONST 2 (20)
23 STORE_FAST 0 (a)
26 LOAD_CONST 0 (None)
29 RETURN_VALUE
,你可以看到名字'a'
由LOAD_FAST
命令的方式加载到堆栈:
13 LOAD_FAST 0 (a)
这是用来抢在功能本地变量的命令(名为FAST
,由于它是相当快比从全球范围加载LOAD_GLOBAL
)。
这与以前定义的全局名称a
无关。这与CPython会假设你打得很好并且生成LOAD_FAST
以参考'a'
这一事实有关,因为'a'
正在中被分配给(即作为本地名称)在函数体内部。
对于一个名称进入,并没有相应的分配功能,CPython中不产生LOAD_FAST
,而是与LOAD_GLOBAL
去,并着眼于全球范围内:
>>> def g():
... print(b)
>>> dis.dis(g)
2 0 LOAD_GLOBAL 0 (print)
3 LOAD_GLOBAL 1 (b)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
所以它出现在解释提前读取整个函数以确定是否使用a
进行分配。这是记录在任何地方?除了检查语法错误外,是否还有其他任何解释器向前看的场合?
在下文中,参考手册的复合语句部分陈述对于函数定义:
函数定义是一个可执行语句。它的执行将当前局部命名空间中的函数名称绑定到函数对象(函数的可执行代码的包装器)。
具体而言,其所结合的名称f
到包含经编译的代码,f.__code__
,即dis
prettifies我们的一个功能对象。
我想你会发现默认情况下python无法从函数内部访问全局变量。你将不得不明确声明你的意思是使用全局。 (btw不要使用全局变量)。 – quamrana
@quamrana不真实。如果您将作业移除到本地'a',代码将打印'10'。 – 2rs2ts
对于它的价值,这不是特定于python 3,只是在python 2中测试,并发生相同的事情。 – 2rs2ts