python中的作用域分4种情况:
L:local,局部作用域,即函数中定义的变量;
E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
G:globa,全局变量,就是模块级别定义的变量;
B:built-in,系统固定模块里面的变量,比如int, bytearray等。
搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
x = int(2.9) # int built-in
g_count = 0 # global
def outer():
o_count = 1 # enclosing
def inner():
i_count = 2 # local
变量的性质根据修改的顺序先来后到排序,如下两个例子:
A:
count = 10
def outer():
print(count) #输出10
outer()
B:
count = 10
def outer():
count = 100
print(count) #输出100
outer()
print(count)#输出10
A代码中count属于外部作用域中的变量,如果在outer中直接调用,那么默认调用的就是外部作用域中的count,因此A代码的输出为10.
B代码中outer函数试图修改count值,因为一个不在局部作用域里的变量默认只读,所以无法修改,因此Python会在当前的局部作用域内创建一个新的变量,该变量与外部的count同名,但是并非同一变量,所以在局部作用域内输出100,而在外部作用域内输出10.
C:
count = 10
def outer():
global count
count = 100
print(count)#输出100
outer()
print(count)#输出100
A,B代码都无法实现修改外部作用域的变量值的目的,因此我们引入了global关键字,如C代码所示,用关键字global声明count之后,那么count的作用域就不只是局部,而是全局作用域,因此在outer中修改count,外部的count值也变化了,两次都打印了100.
C代码中的global关键字只对所有函数外层的变量起作用,即全局作用域,但是如果想对嵌套作用域中的变量进行修改,就需要nonlocal关键字,如D代码所示:
count=200
def outer():
count = 10
def inner():
nonlocal count
count = 20
print(count)#输出20
inner()
print(count)#输出20
outer()
print(count)#输出200
inner函数中的count被nonlocal声明后,值被修改为20,因此嵌套作用域的count值也被修改为20,但是全局作用域的count并未被修改,仍然为200。
x=100#全局变量
def f1(x):
k=200#闭包变量
def f2():
nonlocal k#声明闭包作用域
global x#声明全局作用域
x*=x,这里只改变了global和local作用域的值,并未改变f1作用域的值
k*=k
print('k1' + str(k))#输出40000
print('x1' + str(x))#输出10000
f2()
print('k2' + str(k))#输出40000
print('x2' + str(x))#输出100,这里还是f1作用域,所以x的值未变
f1(x)
print('x3' + str(x))#输出10000