Py装饰器
装饰器:
1.定义,什么是装饰器
装饰器本质是一个函数,它是为了给其他函数添加附加功能2.装饰器的两个原则
原则1 不修改被修饰函数的源代码原则2 不修改被修饰函数的调用方式
3.首先来看一个统计运行时间的程序
import time def cal(l): start_time=time.time() res=0 for i in l: time.sleep(0.02) res=i+res stop_time=time.time() print('函数的运行时间是%s' %(stop_time-start_time)) cal(range(0,100))
4.但是有可能其他函数还有很多,如果在执行其他的程序的时候也想计算一下
运行时间,就要每次重新写上这个,十分麻烦,所以需要装饰器
装饰器=高阶函数+函数嵌套+闭包函数嵌套定义:def里面再def一个
高阶函数定义:函数接收的参数是一个函数名或者函数返回值是一个函数名
闭包的定义:包就是变量,闭包就是封装变量。里面的变量名找不到时就往外层找
小型示例(以函数接收的参数是一个函数名来制作):
import time def shit(): time.sleep(3) print('you are eating shit') #以下是装饰器函数测量函数的运行时间 def timmer(func): print(func) start_time=time.time() func() stop_time=time.time() print('函数的运行时间是',(stop_time-start_time)) #主程序,调用方式 timmer(shit) #并不修改原函数 shit()
小型示例2(以函数返回值是一个函数名来制作)
import time def shit(): #原始函数 time.sleep(3) print('you are eating shit') #以下是装饰器函数测量函数的运行时间 def timmer(func): def wrapper(): start_time=time.time() func() stop_time=time.time() print('运行时间为',stop_time-start_time) return wrapper #主程序 res = timmer(shit) #由于返回值是wrapper的地址,所以res是wrapper地址 res() #执行wrapper函数 shit() #可以看见并不影响原函数
5.注意@timemer相当于 shit= timmer(shit)
先把timmer执行了,然后获得的是wrapper的内存地址,然后把shit给wrapper执行了之后再
因此以下要加上装饰器的时候只需要在想加装饰器的函数的前面加上@timmer
示例
#以下是装饰器函数测量函数的运行时间 import time def timmer(func): def wrapper(): start_time=time.time() func() stop_time=time.time() print('运行时间为',stop_time-start_time) return wrapper @timmer def shit(): #原始函数 time.sleep(3) print('you are eating shit') return '是返回值' shit() #加上@timmer之后,直接调用就可以了
但是这个程序存在一个小问题,就是执行加装装饰器之后得不到shit函数里面的
返回值
6.针对上一个程序里面的问题,优化后的方法
#以下是装饰器函数测量函数的运行时间 import time def timmer(func): def wrapper(): start_time=time.time() res=func() stop_time=time.time() print('运行时间为',stop_time-start_time) return res return wrapper @timmer def shit(): #原始函数 time.sleep(3) print('you are eating shit') return '是返回值' shit() #加上@timmer之后,直接调用就可以了
但是这个程序还是有小问题,就是如果要修饰的函数里不止一个参数
比如shit函数变成def shit(ab,cd),那就会运行出错
7.由于不同的函数可能有不同个数的参数,可以进行以下的形式的修改
#以下是装饰器函数测量函数的运行时间 import time def timmer(func): def wrapper(*args,**kargs): start_time=time.time() res=func(*args,**kargs) stop_time=time.time() print('运行时间为',stop_time-start_time) return res return wrapper @timmer def shit(name,age,dap): #原始函数 time.sleep(3) print('you are eating shit') return '是返回值' res=shit('aa',12,56)
解压序列:
如果想从很大的一条列表中抽出头和尾,除了使用[]的方式抽,还可以
使用解压的方式
l1=[23,45,8,4,5,8,4,53,82,254,'as'] a,b,*_,d=l1 #这句话解压把整个列表分成了几部分 print(a) #a是23 print(d) #d是as print(b) #b是45 print(_) #_是除去abd剩下的那些部分
验证功能装饰器
def auth_func(func): def wrapper(*args, **kwargs): username = input('用户名') password = input('密码') if username == 'sb' and password == '123': res=func(*args, **kwargs) return res else: print('用户名或者密码错误') return wrapper @auth_func def index(): print('欢迎来到主页') @auth_func def home(): print('欢迎回家 ') index() home()
以上程序有一个缺点,已经成功登陆过一次后,刷新下一个欢迎回家
时还需要重新输入用户名和密码
改良:加入登录状态的判别
时还需要重新输入用户名和密码
改良:加入登录状态的判别
user_dic={'login':False} def auth_func(func): def wrapper(*args, **kwargs): if user_dic['login']==1: res=func(*args, **kwargs) return res username = input('用户名') password = input('密码') if username == 'sb' and password == '123': user_dic['login']=1 res=func(*args, **kwargs) return res else: print('用户名或者密码错误') return wrapper @auth_func def index(): print('欢迎来到主页') @auth_func def home(): print('欢迎回家 ') index() home()
给装饰器加上参数属性:
user_dic={'login':False} def aurhorlog(authortype=0): #外面可以嵌套多一层,这样可以指定传多点参数 def auth_func(func): #上面那层有authortype,因此下面可以直接操作这参数 def wrapper(*args, **kwargs): if user_dic['login']==1: res=func(*args, **kwargs) return res username = input('用户名') password = input('密码') if username == 'sb' and password == '123': user_dic['login']=1 res=func(*args, **kwargs) return res else: print('用户名或者密码错误') return wrapper return auth_func #@aurhorlog()是语法糖,它相当于下面的几句话 # auth_func = aurhorlog(authortype=1) # wrapper = auth_func(index) # index=wrapper() @aurhorlog() def index(): print('欢迎来到主页') @aurhorlog() def home(): print('欢迎回家 ') index() home()
重点:装饰器格式
#装饰器总共是三层 def fun(ptcanshu1=1): #第一层的里面可以弄一个普通参数 def fun1(func): #第二层里是func,它代表着准备要被装饰的函数 def wrapper(): #第三层里不放参数 print('hello') func() #此处为调用要被装饰的函数 return wrapper return fun1 @fun() def shit(): print('shit') shit()
重点:如果三层装饰器的普通参数不够用可以这样做
def pt1(ptcanshu2=1): def pt2(ptcanshu3=3): def fun(ptcanshu1=1): #第一层的里面可以弄一个普通参数 def fun1(func): #第二层里是func,它代表着准备要被装饰的函数 def wrapper(): #第三层里不放参数 print('hello') func() # 此处为调用要被装饰的函数 return wrapper return fun1 return fun() return pt2() @pt1() def shit(): print('shit') #如果要装饰函数就需要取到最内层的wrapper shit()