闭包函数的基础知识
上期文章
1. 函数装饰器
2.闭包
2.1变量作用域
python有3种变量作用域
- 模块全局作用域:在类或函数外部分配定义的。
- 函数局部作用域:通过参数或者在函数主体中定义的。
- 第3种作用域:闭包中的变量环境
2.2全局变量和局部变量
def fun(a):
print(a)
print(b)
fun(10)
10
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[4], line 5
2 print(a)
3 print(b)
----> 5 fun(10)
Cell In[4], line 3, in fun(a)
1 def fun(a):
2 print(a)
----> 3 print(b)
NameError: name 'b' is not defined
在函数 fun(a) 中打印局部变量a 和未知变量b,这里b没有绑定,所以报错
修改如下
def fun(a):
print(a)
# 这里是一个只读变量,先从局部域没有找到,再从全局域找到b
print(b)
# 先绑定全局变量b 再调用fun(10)就没问题了
b = 5
fun(10)
另一个例子:
# 定义全局变量 b并绑定
b =5
def fun(a):
print(a)
# 打印一个还未绑定的局部变量,肯定会报错
print(b)
# 这里又定义了局部变量b,编译器会认为b是局部变量
b=9
fun(10)
在函数fun(a)中,先打印a,没问题,因为a是一个参数(数据局部变量)
接着打印b时报错说是不能访问局部变量b,因为b=9在print(b)之后定义,而且并未查找全局变量b
python不要求声明变量,但是它会假定在函数主题中赋值的变量是局部变量。
我们本意是想在函数中访问全局变量b,如果想在函数中把b当成全局变量,就要使用global关键字声明b
修改如下:
b =5
def fun(a):
# 使用全部变量b,可读写
global b
print(a)
print(b)
b=9
fun(10)
2.3闭包
闭包是一个函数嵌套另一个函数的形式,如下:
def closer():
#没有赋值,本身又是一个可变类型
value = []
def fun(a):
value.append(a)
total = sum(value)
return total / len(value)
return fun
#调用closer()返回 fun函数引用
avg = closer()
#调用avg = fun函数引用,此时注意closer作用域已经“消失了”
#但是 自由变量 value引用依然存在
avg(10)
#连续调用发现value作用域一直存在
avg(40)
avg(15)
fun函数中引用的非全局变量(value),和局部变量(a,total) 来自于外部函数 closer()的作用域。这种形式的嵌套函数就叫闭包。
这种闭包函数隐藏了一些数据比如(value),value是 自由变量:指未在局部作用域中绑定的变量(即没有赋值)
综上所述:闭包是一个函数,它保留了定义函数时存在的自由变量的绑定。再调用函数avg时,虽然closer作用域不可用了,但是仍能访问那些绑定(value)
2.4 nonlocal
我们将上面的例子修改一下:
def closer():
#绑定具体数值,本身又是不可变类型
count = 0
total = 0
def fun(a):
#这里会把count total 理解为局部变量(fun内部)
count = count +1
total = total + a
return total / count
return fun
#调用closer()返回 fun函数引用
avg = closer()
avg(10)
avg(40)
avg(15)
上面问题是在closer函数中定义的count = 0 total = 0已经有了绑定对象,他们不是自由变量
在fun函数中对count赋值,将重新创建count局部变量,因为没有提前定义,所以报错。
我们使用nonlocal声明count,total即可解决此问题,表示fun函数访问的是他的外部函数的变量,将他们变为自由变量。
def closer():
count = 0
total = 0
def fun(a):
#告诉编译器我使用的是外部变量 count total(closer函数域的)
nonlocal count,total
count = count +1
total = total + a
return total / count
return fun
#调用closer()返回 fun函数引用
avg = closer()
avg(10)
avg(40)
avg(15)
原文地址:https://blog.csdn.net/bai_yechuang2012/article/details/144300605
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!