装饰器高潮
一、概述
我们之前介绍了大幅片的内容,感觉跟装饰器半毛钱关系都没有,其实不然,我们分别详细阐述了高阶函数和内置函数,下面我们就来讲讲什么是真正的装饰器。
二、装饰器定义
首先装饰器实现的条件:高阶函数+嵌套函数 =》装饰器
1、定义
import time def timer(func): #func = sample_1 timer(sample_1) def deco(): start_time = time.time() func() #run sample_1() stop_time = time.time() print("the func time is %s" %(stop_time-start_time)) return deco @timer #timer来装饰sample_1 def sample_1(): #相当于 sample_1 = timer(sample_1) time.sleep(3) print('it is sample_1') #直接执行函数 sample_1() #输出结果 it is sample_1 the func time is 3.0023279190063477
执行步骤:
- 执行timer函数,timer(sample_1) 返回值赋值给sample_1变量,即sample_1=timer(sample_1)
- 此时的sample_1的值是执行timer函数返回值deco,即sample_1=deco
- 所以执行sample_1,其实就是执行的是deco函数,sample_1()其实就是执行deco()函数。
2、执行函数带参数
我们先来试试,如果被装饰的函数需要传入参数怎么办?
import time def timer(func): #func = sample_X timer(sample_X) def deco(): start_time = time.time() func() #run sample_1() stop_time = time.time() print("the func time is %s" %(stop_time-start_time)) return deco @timer def sample_2(name,age): #相当于 sample_2 = timer(sample_2) time.sleep(3) print("name is %s,age is %s" %(name,age)) #直接执行函数 sample_2('seven_day',30) #输出结果
Traceback (most recent call last):
File "/Users/lin/Desktop/lin/py/装饰器/前奏1.py", line 25, in <module>
sample_2('seven_day',30)
TypeError: deco() takes 0 positional arguments but 2 were given
很显然是错误的,错误的。因为这边执行的test2函数其实就是执行的deco函数,deco函数体内的func()其实就是执行sample_2函数,但是,sample_2需要传入name和age两个参数,所以报错。那怎么解决呢?我们只能传入参数了,但是你又不能确定传入几个参数,所以我们只能用非固定参数传参。代码如下:
import time def timer(func): #func = sample_X timer(sample_X) def deco(*args,**kwargs): #传入非固定参数 start_time = time.time() func(*args,**kwargs) #传入非固定参数 #run sample_1() stop_time = time.time() print("the func time is %s" %(stop_time-start_time)) return deco @timer #timer来装饰sample_1 def sample_1(): #相当于 sample_1 = timer(sample_1) time.sleep(3) print('it is sample_1') @timer def sample_2(name,age): #相当于 sample_2 = timer(sample_2) time.sleep(3) print("name is %s,age is %s" %(name,age)) #直接执行函数 sample_1() sample_2('seven_day',30)
#输出结果
it is sample_1
the func time is 3.00357723236084
name is seven_day,age is 30
the func time is 3.001821994781494
三、执行函数有返回值
上面的例子,被调用的函数都没有返回值,那如果,我们被调函数有返回值,该如何做呢?
user,passwd = "seven",'123' def auth(auth_type): #传递装饰器的参数 print("auth func",auth_type) def outer_wrapper(func): # 将被装饰的函数作为参数传递进来 def wrapper(*args, **kwargs): # 将被装饰的函数作为参数传递进来 print("auth wrapper age",*args,**kwargs) username = input("请输入用户名:").strip() password = input("请输入密码:").strip() if auth_type == "local": if user == username and passwd == password: print("\033[32;1m user has passed authentication\033[0m") res = func(*args, **kwargs) print("----after authentication----") return res else: exit("\033[31;1mIvalid username or password\033[0m") elif auth_type == "ldap": print("ldap") return wrapper return outer_wrapper def index(): print("welcome to index page") @auth(auth_type="local") #带参数装饰器 def home(): print("welcome to home page") return "from home" @auth(auth_type="ldap") #带参数装饰器 def bbs(): print("welcome to bbs page") index() home() bbs()
重上面的例子可以看出,执行步骤:
- outer_wrapper = auth(auth_type="local")
- home = outer_wrapper(home)
- home()
所以这个函数的作用分别是:
- auth(auth_type) 传递装饰器的参数
- outer_wrapper(func) 把函数当做实参传递进来
- wrapper(*args,**kwargs) 真正执行装饰的函数