函数嵌套 闭包 与 函数作用域
一、作用域
函数的命名空间可以作用域可以划分为:LEGB四种,使用缩进来规定。 不同的命名空间的变量可以同名。
本地 local 本地使用,在函数缩进中,代表着本地缩进
封闭 enclosing 在嵌套函数中使用,
全局 global 任何地方都能使用,模块的顶层
内置 Builtin 内置,比如 int,内置函数等。
1.1 作用域的范围 与 搜索次序
从里到外所搜: 本地 -》封闭-》全局
1.2 作用域规则
搜索规则: 本地 -》封闭-》全局 从里到外 一层层修改。
修改规则: 本地可以引用全局的变量,但是不可以修改上一级的变量。
(注意复杂的数据结构,list,dict 修改他们的二级数值,并不算修改本身。详见:深浅拷贝章节)
i = 1 def test(): i += 1 # 等同与 i = i + 1 ,这里的i 都是全局变量。 在规则中,不可以修改全局变量。 test() UnboundLocalError: local variable 'i' referenced before assignment
对于复杂结构的数据:
li = [1,2,3,4] def test(): li[0] = 100 li.append(200) # 对于复杂的数据节后,可以直接修改二级的,并不算修改本身 test() print(li) 结果: [100, 2, 3, 4, 200]
二、内嵌函数
在一级函数内部,定义函数,可在内部直接运行函数,也可以返回函数,这就是内嵌函数,也叫做封闭作用域。
def cal(a, b): def add(a,b): print (a+b) def sub(a,b): print(a-b) def mul(x,y): print (a*b) add(a,b) sub(a,b) return mul cal(1,3)()
三、闭包函数
闭包函数是内嵌函数的升级版本, 返回 内嵌函数名 与 自由变量(非全局变量,是一级函数的变量)的绑定体。
一般函数执行完毕,内部的变量的就消亡了,但是闭包的函数的存在一个封闭空间,不会在一级函数运行完毕而消亡。
def hellow(): s = 'i AM' # 自由变量 def say(): print(s) return say # 返回内嵌函数名,但是绑定了自由变量 x = hellow() x()
闭包函数 也遵循了,不能修改上一级变量的特征。
def hellow(): s = 'i AM' def say(): s += '' #修改上一级变量,报错 print(s) return say x = hellow() x() 运行结果: UnboundLocalError: local variable 's' referenced before assignment
四、修改上一级的变量
上面一直说不能修改和赋值,那一定要修改和赋值呢?
python中引进了 gloable 和 nolocal 两个关键字。
4.1 global
global的两个作用:
-
声明一个全局变量
-
在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)
def func(): global a #声明为全局变量 a = 2 print(a) func() print(a) 计算结果: 2 2
4.2 nolocal
- 不能修改全局变量
- 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变
def add_b(): b = 42 def do_global(): b = 10 print(b) def dd_nonlocal(): nonlocal b # 只对上一层起作用 b = b + 20 print(b) dd_nonlocal() print(b) do_global() print(b) add_b() 计算结果: 10 30 30 42