目录
一、什么是装饰器
装饰器是python中一个很重要的概念,简单来说:从字面意思来讲,就是装饰,强化,对你的函数进行功能是的扩充,并且无需修改被修饰函数的代码,起到装饰、补充的作用
要了解装饰器,我们先了解下什么是闭包函数
闭包函数:在嵌套函数中,如果内部函数对外部函数的变量进行了引用并且返回内部函数,那么内部函数就是闭包函数
我们看一个闭包函数的简单案例,来理解闭包
#定义了func的外部函数,中有c局部变量
def func(a,b):
c = 10
def inner_func():#内部函数inner对外部函数变量c做了引用
s = a + b + c
print(s)
print(locals()) #产看本地的变量
return inner_func #外部函数返回的是一个内部函数
x = func(3,6) #内层函数返回值,用x接收
x() #x的值等于 x =inner_func,是一个函数,所以可以调用
闭包注意点:
1、内部函数可以访问外部函数的不可变变量,但是如果要修改不可变变量,则要加关键字nonlocal进行声明
2、内部函数和外部函数中的变量代码是平级的
3、内部函数只是做了声明,外部函数代码中要进行调用,才会执行内部函数代码
4、内部函数修改全局变量的不可变变量,要加global关键字进行声明
闭包应用小案例:计数器
def counter():
i = 0
def inner_func():
nonlocal i
i +=1
print("执行第{}次".format(i))
return inner_func
x = counter()
x()
x()
x()
二、装饰器的特点
1、函数作为参数
2、要有闭包的特点
装饰器的基本结构案例:
#定义装饰器,对房子进行装饰
def decorate(func): #传输参数hourse为函数
a = 100
def wrapper(): #定义内部函数,并调用func
func()
print("开始装饰毛坯房")
print("开始了{}地板".format(a))
print("开始刷漆")
return wrapper
@decorate #hourse是被装饰的函数,(在@下面就是被装饰的函数) decoreate就是装饰器
#简单定义一个毛坯房
def hourse():
print("这个是一个毛坯房")
hourse()
我们来简单梳理下上面的执行加载过程:
1、hourse 是被装饰的函数
2、decorate是装饰器
3、开始执行decorate,然后decorate返回值赋值给hourse
我们通过案例来验证下上面的结论:
def decorate(func):
a = 100
print("开始进行装饰")
def wrapper(*args,**kwargs):
func(*args,**kwargs)
print("一共铺砖{}块".format(a))
print("开始进行刷漆")
print("开始进行家具布置")
print("装饰完成")
print(wrapper,1)
return wrapper
@decorate
def hourse():
print("这是一个毛坯房")
print(hourse)
上面代码执行结果:
开始进行装饰
装饰完成
<function decorate.<locals>.wrapper at 0x0000022D01A70EA0> 1
<function decorate.<locals>.wrapper at 0x0000022D01A70EA0>
注意观察,得出如下
1、当我们去装饰hourse时,没有进行调用,只是打印hourse,你观察函数的内存地址,和指向的就是wrapper内部函数的地址
2、执行顺序。
2.1 执行decorate函数
2.2 加载wrapper,注意只是加载,但是没有执行
2.3 hourse作为实参传入到decorate中,并decorate的返回值赋值个hourse
当我们把 print(hourse) 改为调用 hourse():得到的结果是:
开始进行装饰
装饰完成
<function decorate.<locals>.wrapper at 0x0000023E47BF0EA0> 1
这是一个毛坯房
一共铺砖100块
开始进行刷漆
开始进行家具布置
进一步说明了我们上面的结论
我们进一步来说明,当我们被装饰的函数有参数,并且装饰器也有参数的情形:
def outer(a):
def decorate(func):
def wrapper(*args,**kwargs):
func(*args,**kwargs)
print("---->开始第{}块铺地板".format(a))
return wrapper
return decorate
@outer(a=10)
def house(ti):
print("房子到期日期是{}".format(ti))
house('6月10日')
当三层函数嵌套(装饰器有参数):
1、outer函数最外层,用来接收装饰器的参数
2、decorate第二层,用来接收被装饰的函数func
3、最内层函数,用来接收被装饰的函数的实参,因为我们不确定实参个数,所以通常是使用*args 和**kwargs来进行接收实参
最后,我们来看一个应用的实际案例:
场景:当我们没有登录到淘宝,可以查看商品信息,但是添加到购物车时,就会提示让你登录,或者你访问淘票票进行查看电影,当你点击电影查看票务详情,就会提示让你登录,我们就看看这段使用装饰器该怎么实现
代码如下:
import time
is_login = False
def login():
username = input("请输入用户名:")
password = input("请输入用户密码:")
if username == 'admin' and password == '123456':
return True
else:
return False
#添加装饰器
def decorater(func):
def wrapper(*args,**kwargs):
global is_login
if is_login:
func(*args,**kwargs)
else:
print("用户没有登录,请登录")
is_login = login()
return wrapper
@decorater
def pay(n):
print("正在支付中.....")
time.sleep(2)
print("支付完成,一共支付了{}元".format(n))
pay(3000)
pay(800)
完结总结:装饰器是一个重要模块,后续再flask或Drango中会有很多应用,这里做个详细的复盘笔记,加深自己印象