python中的做用域分4种状况: L:local,局部做用域,即函数中定义的变量;
E:enclosing,嵌套的父级函数的局部做用域,即包含此函数的上级函数的局部做用域,但不是全局的;
G:globa,全局变量,就是模块级别定义的变量; B:built-in,系统固定模块里面的变量,好比int, bytearray等。 搜索变量的优先级顺序依次是:做用域局部>外层做用域>当前模块中的全局>python内置做用域,也就是LEGB。python
1web 2闭包 3函数 4ui 5spa 6code 7ci |
|
固然,local和enclosing是相对的,enclosing变量相对上层来讲也是local。
在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的做用域,其它的代码块(如if、try、for等)是不会引入新的做用域的,以下代码:
1 2 3 4 |
|
这个是没有问题的,if并无引入一个新的做用域,x仍处在当前做用域中,后面代码可使用。
1 2 3 4 |
|
def、class、lambda是能够引入新做用域的。
一个不在局部做用域里的变量默认是只读的,若是试图为其绑定一个新的值,python认为是在当前的局部做用域里建立一个新的变量,也就是说在当前局部做用域中,若是直接使用外部做用域的变量,那么这个变量是只读的,不能修改,如:
1 2 3 4 5 6 7 |
|
这里第一个print中,使用到了外部做用域的count,这样后面count就指外部做用域中的count了,再修改就会报错。 若是没使用过这个变量,而直接赋值,会认为是新定义的变量,此时会覆盖外部做用域中变量,如:
1 2 3 4 5 6 |
|
内部做用域中直接声明了count=100,后面使用count都是内部做用域的了。
当内部做用域想修改外部做用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局做用域(global做用域)上的,就要使用global先声明一下,代码以下:
1 2 3 4 5 6 7 8 9 |
|
global关键字声明的变量必须在全局做用域上,不能嵌套做用域上,当要修改嵌套做用域(enclosing做用域,外层非全局做用域)中的变量怎么办呢,这时就须要nonlocal关键字了
1 2 3 4 5 6 7 8 9 10 11 |
|
(1)变量查找顺序:LEGB,做用域局部>外层做用域>当前模块中的全局>python内置做用域;
(2)只有模块、类、及函数才能引入新做用域;
(3)对于一个变量,内部做用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部做用域的变量;
(4)内部做用域要修改外部做用域变量的值时,全局变量要使用global关键字,嵌套做用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个关键字,就能完美的实现闭包了。