本文试图整理一个清晰的思路来判断python中变量的作用域.
核心要点
- 总共有4个作用域:L(local, 本地作用域, 作用于函数内部), E(enclosing, 嵌套作用域, 作用于上一层函数), G(global, 全局作用域, 作用于整个模块), B(built-in, 内置作用域)
- 预编译的时候会按照Lolca-Enclosing-Global-Builtin的顺序根据变量赋值的位置进行类型判断.
- 执行的时候会根据变量类型去找对应的值
几个例子
下面例子演示了如何在一个函数中读取全局变量
var = 1
def test():
print(var)
test()
----------output------------
1
执行过程如下:
1.生成test函数的时候(line-2 to line-3).
1. 发现test函数中没有对var的赋值操作, 所以认为不是Local作用域.
2. 发现var变量在global处有赋值操作(line-1), 所以认为test函数中的var是global作用域.
2.执行test函数的时候(line-4), 当在test函数中打印var的时候(line-3)会读取global作用域中的var值, 即1.
下面这个例子演示了在一个函数中如果不进行显示声明, 是不能对全局变量进行写操作的.
var = 1
def test():
print(var)
var = 2
test()
----------output------------
Traceback (most recent call last):
File "test.py", line 5, in <module>
test()
File "test.py", line 3, in test
print(var)
UnboundLocalError: local variable 'var' referenced before assignment
执行过程如下:
1.生成test函数的时候(line-2 to line-4).
1. 发现test中有对var的赋值(line-4), 所以认为var是Local作用域.
2. 执行test函数(line-6), 执行到打印var的时候(line-4),会在Local范围内寻找var的值, 但是此时var还没有被赋值, 所以会报错.
下面这个例子演示了通过显示声明作用域后能够在函数中对全局变量进行写操作.
var = 1
def test():
global var
print(var)
var = 2
test()
print(var)
----------output------------
1
2
执行过程如下:
1. 生成test函数(line-2 to line-5).
1. 发现test中有对var的显式声明global作用域(line-3), 所以认为var是global作用域.
2. 执行test函数(line-6).
1. 首先在test函数中打印的时候(line-4)会在global范围内寻找var的值, global作用域的var已经在line-1赋值过了, 所以打印1
2. 在test函数中对var赋值的时候(line-2), 是对global作用域中的var赋值
3. 打印var(line-7)
1. 打印global作用域中的var值, 即2
下面这个例子演示了被嵌套的函数必须通过显示声明类型才能够对上一级函数中的变量进行写操作.
var = 1
def test(var):
def add():
nonlocal var
var = var + 1
add()
print(var)
return var
test(var)
print(var)
----
2
1
执行过程如下:
1. 生成test函数(line-2 to line-8).
1. 发现test函数中没有对var的赋值, 所以认为var是Local作用域.
2. 生成add函数(line-3 to line-5).
1. 发现有nonlocal的显示声明(line-4), 所以认为var是Enclosing作用域, 即上一层test函数中的local作用域.
3. 执行test函数(line-9)
1.执行add函数(line-6)
1. 在对var加一的时候(line-5), 由于之前判定var是add函数中的enclosing作用域, 即test函数中的local作用域, 所以是对test函数中的local作用域的var进行加一操作.
2. 打印var的(line-6),打印的是local作用域的var变量, 该变量在add函数中进行了加一操作, 所以结果是2.
4. 打印var(line-10)
1. 这里打印的是global作用域中的var, 在line-1处进行过赋值为1, 所以结果是1.
参考文献
https://www.cnblogs.com/fireporsche/p/7813961.html
https://www.cnblogs.com/JohnABC/p/4076855.html
https://baijiahao.baidu.com/s?id=1629972259474819006&wfr=spider&for=pc