第一部分:全局变量和局部变量
全局变量:在全局作用域或者局部作用域下都能正常访问的变量
局部变量:只要在局部作用域下才能正常访问的变量,一旦函数执行完毕就没跟着垃圾回收机制而销毁
那我们是否有办法把函数内部的局部变量保留呢?
当然有,就是使用闭包
在函数嵌套的前提下,内部函数使用的外部函数的变量,并且外部函数返回了内部函数,这就称这个内部函数为闭包
第二部分:函数的闭包
闭包的构成有三个条件
- 有嵌套
- 有引用
- 有返回
def func():
result = 0
def inner(num):
nonlocal result
result += num
print(result)
return inner
f = func()
f(1)
f(2)
f(3)
这是一个简单的例子,我来详细的说明一下:
- func函数是我们定义的一个函数,内部嵌套了一个inner函数 -------- 有嵌套
- 在inner函数中,我们使用nonlocal关键字引用了外部函数的result --- 有引用
- 在func函数我们返回了inner函数的内存地址 ------------------------------- 有返回
那么这个inner函数就是外部函数func的闭包
回想闭包的作用:保留局部变量,在函数执行完毕后可以不回收我们的result
执行上述代码,我们可以发现,每次执行完func()函数后result变量并没有回收,保留了下来,并且可以不断的进行累加。
这就是闭包的作用。
第三部分:装饰器
装饰器本质上就是一个闭包,它的作用是:
- 不改变函数的名称
- 不改变函数的调用方式
- 给函数增加新的功能
假设我们已经实现了一个评论功能的函数,现在想给它在评论之前新增一个登录的功能,但是不改变函数的调用方式和名称,在这时候就可以使用装饰器了。
def cheak(fn):
def inner():
print('登录功能开发')
fn()
return inner
def comment():
print('comment功能')
comment = cheak(comment)
comment()
在上面的代码中,我们声明了一个和comment()函数同名的一个变量,用来接受cheak()的返回值
在cheak()函数中,有嵌套inner函数,在inner函数内引用了外部cheak函数的变量fn,同时又有返回inner函数,同时满足闭包构成的三个条件
我们声明的comment变量,接受的是inner函数的内存地址,inner函数是新增了一个登录功能在评论功能之前
装饰器还有一种更简单的写法:
在函数定义的前一行添上@外部函数名称,效果与上面是相同的
def cheak(fn):
def inner():
print('登录功能开发')
fn()
return inner
@cheak
def comment():
print('comment功能')
comment()