我在Python中遇到了一些非常奇怪的全局变量处理。我希望有人能解释和证明这些惊喜!
A) 此代码按预期打印10:
def func():
print(a)
a = 10
func()
B) 这段代码抛出了一个关于过早引用的异常:
def func():
print(a)
a += 1
a = 10
func()
C) 但这个代码打印[10]如预期:
def func():
print(a)
a.append(1)
a = [10]
func()
因此,我可以得出结论,a
的类型改变了它的范围,此外,后来甚至还没有到达的语句也改变了对a
的看法。我知道我可以在函数开始时使用global a
,但它相当冗长。
有人能告诉我Python使用什么规则来处理其奇怪的范围吗?
第二个实例重新绑定a
,因此编译器为其生成本地访问。其他两个实例只读取a
,因此执行正常的全局范围搜索。
基本上有两个规则:
- 当您只读取一个变量(在作用域内)时,Python将沿着作用域链向上移动,直到找到该名称的变量
- 当您至少对一个变量写入一次时,Python将始终在当前作用域中创建该变量
但是,您可以更改#2的行为:
- 如果希望名称引用模块级变量,可以使用
global my_module_variable
。现在写入my_module_variable
时,Python将而不是创建局部变量 - 从Python3开始,您还可以使用一个名称来引用封闭作用域中的变量:使用
nonlocal my_non_local_variable
使其引用最近的封闭作用域内的变量
代码中的问题
B) 您正在使用+=
:您正在尝试写入变量。因此,第2条规则有效,它将写入当前作用域中的一个变量。然而,它也必须从中读取(print(a)
),但变量还没有值,因为您以前没有向它写入过。Python不允许在函数中混合使用规则1.
和规则2.
。
如果您希望func()
处理a = 10
变量,您可以这样更改代码:
>>>> def func()
global a
print(a)
a += 1
>>>> a = 10
>>>> func()
10
>>>> func()
11