如果不使用global 关键字,则无法在函数内访问全局变量; (很好)但我没想到会出现以下情况:
案例一:
a = 1
def f():
a += 1
print(a)
>>> f()
...
UnboundLocalError: local variable 'a' referenced before assignment
我推测的原因:函数在其本地范围内找不到变量 a。
案例二:
a = 1
def f():
print(a)
>>> f()
1
但是现在,该函数在其本地范围内找到变量 a。
矛盾,我在前面的案例中推测的原因。
为什么会这样?
这是因为对于你的第二个例子,编译器试图用一些魔法来帮助你。在这种情况下
def f():
print(a)
这是它缩减为的字节码:
dis.dis(f)
2 0 LOAD_GLOBAL 0 (print)
3 LOAD_GLOBAL 1 (a) #aha!
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
您可以看到,由于您从未在 f
范围内分配给 a
,因此编译器知道您必须指的是全局.
当您开始分配给a
时,现在编译器不会尝试帮助您。除非您明确告诉它 a
是全局的,否则它会将其视为本地的。
def g():
x += 1
dis.dis(g)
2 0 LOAD_FAST 0 (x) #note no assumption that it is global
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_FAST 0 (x)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
现在你可以问这个问题了,好吧,但是为什么编译器在你的第一个例子中没有帮助你呢?一种解释方式当然是“显式优于隐式”。虽然编译器当然在你的第二个例子中隐含地做了一些事情,所以也许这不是一个令人满意的解释:)。
主要归结为这就是 Python 的工作原理,我想说。如果您分配给一个变量,python 将将其视为该范围的局部变量,除非您另有说明。所以你的声明:
Global variables cannot be accessed within a function without using
the global keyword
不太正确。您可以从外部作用域访问变量,但您不能在未明确声明的情况下分配给所述变量。
旁注,这是完全合法的:
x = [1]
def f():
x[0] += 1
f()
#x is now [2]
这可能令人困惑 :-)。这是因为在这种情况下,您没有在 x
持有的引用上分配任何东西; +=
运算符实际上调用列表的 __setattr__
方法来更改属性。在 python 2 中,这个技巧经常被用作没有 nonlocal
关键字的解决方法。