python中的闭包和装饰器
目录
一.闭包
1.闭包的用途和用法
简单闭包
2.nonlocal关键字的作用
ATM闭包实现
注意事项
小结
二.装饰器
装饰器的一般写法(闭包写法)
装饰器的语法糖写法
一.闭包
1.闭包的用途和用法
先看如下代码:
通过全局变量account_amount来记录余额
尽管功能实现是ok的,但是仍有问题:
- 代码在命名空间上(变量定义)不够干净、整洁
- 全局变量有被修改的风险
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
将上述代码转为闭包的写法就是:
简单闭包
#简单闭包
def out(data):
def a(data1):
print(f"{data}<{data1}>{data}")
return a
test=out("asdf")
test("1")
test("2")
test("3")
print("---------------------")
test=out("abc")
test("1")
test("2")
test("3")
结果是
代码中的test已经变成了函数a,之后就是引用函数a的参数
test得到的是一个内部函数,也称为闭包函数。当我们需要修改外部变量的时候,重新调用外部函数就可以了
2.nonlocal关键字的作用
除了重新调用外部函数去修改外部变量,还可以用nonlocal关键字
看下面代码:
当我们想直接修改外部变量income时,程序报错,不能够访问这说明如果我们想修改闭包引用的外部变量的话,我们需要加上nonlocal关键字去修饰一下。
#简单闭包
def out(income):
def inner(num):
nonlocal income
income+=num
print(income)
return inner
a=out(1000)
a(100)
结果是
ATM闭包实现
#ATM实现
def atm(num):
def make_money(money,pd=True):
nonlocal num
if pd:
num += money
print(f"存款{money},余额有{num}")
else:
num -= money
print(f"存款-{money},余额有{num}")
return make_money
a=atm(1000)
a(200)
a(500)
a(600,False)
结果是
注意事项
优点,使用闭包可以让我们得到:
- 无需定义全局变量即可实现通过函数,持续的访问、修改某个值
- 闭包使用的变量的所用于在函数内,难以被错误的调用修改
缺点:
- 由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存
小结
1.什么是闭包
定义双层嵌套函数,内层函数可以访问外层函数的变量将内存函数作为外层函数的返回,此内层函数就是闭包函数
2.闭包的好处和缺点
- 优点:不定义全局变量,也可以让函数持续访问和修改一个外部变量
- 优点:闭包函数引用的外部变量,是外层函数的内部变量。作用域封闭难以被误操作修改
- 缺点:额外的内存占用
3.nonlocal关键字的作用
在闭包函数(内部函数中)想要修改外部函数的变量值需要用nonlocal声明这个外部变量
二.装饰器
装饰器其实也是一种闭包,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能。
希望给sleep函数,增加一个功能:
- 在调用sleep前输出:我要睡觉了
- 在调用sleep后输出:我起床了
我们可以直接
但是也可以用装饰器处理
装饰器的一般写法(闭包写法)
def sleep():
import random
import time
print("睡梦中……")
time.sleep(random.randint(1,5))#随机暂停1~5秒
def out(func):
def inner():
print("开始睡觉了")
func()
print("睡醒了")
return inner
a=out(sleep)
a()
##########法二
print("______________")
def sleep():
import random
import time
print("睡梦中……")
time.sleep(random.randint(1,5))#随机暂停1~5秒
def out():
def inner():
print("开始睡觉了")
sleep()
print("睡醒了")
return inner
a=out()
a()
结果是
装饰器的语法糖写法
def out(func):
def inner():
print("开始睡觉了")
func()
print("睡醒了")
return inner
@out
def sleep():
import random
import time
print("睡梦中……")
time.sleep(random.randint(1,5))#随机暂停1~5秒
sleep()
结果是
python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。