首先装饰器实现的条件:
高阶函数+嵌套函数 =》装饰器
1.首先,我们先定义一个高级函数,去装饰test1函数,得不到我们想要的操作方式
import time #定义高阶函数 def deco(func): start_time = time.time() func() stop_time = time.time() print("the func run time is %s"%(stop_time-start_time)) #装饰test1函数 def test1(): time.sleep(3) print("in the test1") #deco(test1) #这样操作就改变函数的调用方式 , 怎样操作不改变调用方式 test1 = deco(test1) #想想前提是用return 返回值 #输出 in the test1 the func run time is 3.0002999305725098
2 .用高阶函数的返回值方法,得到了想要的调用方式,但是结果不是想要的,一直到现在我们一直在用高阶函数
import time #定义高阶函数 def deco(func): start_time = time.time() return func() stop_time = time.time() print("the func run time is %s"%(stop_time-start_time)) #装饰test1函数 def test1(): time.sleep(3) print("in the test1") test1() #调用方式问题解决了,但是结果不是想要的结果 结果 in the test1
3 . 再用嵌套函数得到了我们想要的结果和不变的调用方式(哇喔,是不是好牛X)
import time #定义内置函数 def timmer(func): #timmer(test1) func=test1 def deco(): start_time = time.time() func() #run test1() stop_time = time.time() print("the func run time is %s"%(stop_time-start_time)) return deco #重点的重点 #装饰test1函数 @timmer # 相当于test1 = timmer(test1) 牛X的方法 def test1(): time.sleep(3) print("in the test1") #直接执行test1函数 test1() #输出 in the test1 the func run time is 3.0002999305725098
4. 我们用装饰器去装饰一个带参数的函数会怎么样?
import time def timmer(func): def deco(): start_time = time.time() func() #run test2() 这里没有参数,报错 stop_time = time.time() print("the func run time is %s"%(stop_time-start_time)) return deco @timmer def test2(name,age): print("name:%s,age:%s"%(name,age)) test2() #输出 Traceback (most recent call last): File "D:/PycharmProjects/pyhomework/day4/装饰器/装饰器高潮.py", line 16, in <module> test2() File "D:/PycharmProjects/pyhomework/day4/装饰器/装饰器高潮.py", line 6, in deco func() #run test2() TypeError: test2() missing 2 required positional arguments: 'name' and 'age' #缺少传入name和age参数
结果:很显然是错误的。因为这边执行的test2函数其实就是执行的deco函数,deco函数体内的func()其实就是执行test2函数,但是,test2需要传入name和age两个参数,所以报错。那怎么解决呢?
5. 我们只能传入参数了,但是你又不能确定传入几个参数,所以我们只能用非固定参数传参。代码如下:(哇喔,这个更牛X)
import time def timmer(func): #timmer(test1) func=test1 def deco(*args,**kwargs): #传入非固定参数 可以面对各种参数 start_time = time.time() func(*args,**kwargs) #传入非固定参数 stop_time = time.time() print("the func run time is %s"%(stop_time-start_time)) return deco #不带参数 @timmer # 相当于test1 = timmer(test1) def test1(): time.sleep(3) print("in the test1") #带参数 @timmer def test2(name,age): print("name:%s,age:%s"%(name,age)) #调用 test1() test2("qianduoduo",22) #输出 #test1 in the test1 the func run time is 3.0010883808135986 #test2 name:qianduoduo,age:22 the func run time is 0.0 #test2
6.我就问还有没有终极版的,答案是:有
前面的都是小高潮(基本上也能满足百分之九十的需求),现在正式介绍终极的高潮版的 语法糖(我也不知道为什么取这个名字)也叫装饰器
import time user,passwd = 'qian','zxc123' def auth(func): def wrapper(*args,**kwargs): #包装 username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("\033[32;1mUser has passed authentication\033[0m") func(*args,**kwargs) else: exit("\033[31;1mInvalid username or password\033[0m") return wrapper def index(): #建立网站的首页 首页不需要登入 print("welcome to index page") @auth #加上装饰器 def home(): #自己的页面,需要登入 print("welcome to home page") @auth def bbs(): #论坛区的页面,需要登入 print("welcome to bbs page") index() home() bbs() 运行结果: #运行很完美,堪称经典之作 welcome to index page Username:qian Password:zxc123 User has passed authentication welcome to home page Username:qian Password:zxc123 User has passed authentication welcome to bbs page
7.走到这地方,我的问题来了,我的home执行完没有任何数据,我现在在home中return一个数据,看代码:
import time user,passwd = 'qian','zxc123' def auth(func): def wrapper(*args,**kwargs): #包装 username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("\033[32;1mUser has passed authentication\033[0m") func(*args,**kwargs) else: exit("\033[31;1mInvalid username or password\033[0m") return wrapper def index(): #建立网站的首页 首页不需要登入 print("welcome to index page") @auth #加上装饰器 def home(): #自己的页面,需要登入 print("welcome to home page") return "from home" #假设这就是我返回的数据 @auth def bbs(): #论坛区的页面,需要登入 print("welcome to bbs page") index() print(home()) #home的执行结果 bbs() 结果: welcome to index page Username:qian Password:zxc123 User has passed authentication welcome to home page None # home的执行结果,没有执行结果 #(虽然装饰器没改变源代码,没改变调用方式,但是改变了执行结果) # 这时候我们怎么办,怎么获得home的返回结果? Username:
8 我们来分析一下,按照顺序①②③
import time user,passwd = 'qian','zxc123' def auth(func): def wrapper(*args,**kwargs): #包装 username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("\033[32;1mUser has passed authentication\033[0m") func(*args,**kwargs) #from home # ① func的执行结果没有传给谁,那就没了,就是None else: exit("\033[31;1mInvalid username or password\033[0m") return wrapper #③wrapper执行了,没有返回值 def index(): #建立网站的首页 首页不需要登入 print("welcome to index page") @auth #加上装饰器 def home(): #自己的页面,需要登入 print("welcome to home page") return "from home" @auth def bbs(): #论坛区的页面,需要登入 print("welcome to bbs page") index() print(home()) #②调用home 时候,就是调用wrapper() bbs()
9 分析完得出以下代码:
import time user,passwd = 'qian','zxc123' def auth(func): def wrapper(*args,**kwargs): #包装 username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("\033[32;1mUser has passed authentication\033[0m") # return func(*args,**kwargs) 函数到这里就结束了 res = func(*args,**kwargs) #增加变量 print("---after authenticaion") #再装饰点其他东西 return res else: exit("\033[31;1mInvalid username or password\033[0m") return wrapper def index(): #建立网站的首页 首页不需要登入 print("welcome to index page") @auth #加上装饰器 def home(): #自己的页面,需要登入 print("welcome to home page") return "from home" @auth def bbs(): #论坛区的页面,需要登入 print("welcome to bbs page") index() print(home()) bbs() 结果 welcome to index page Username:qian Password:zxc123 User has passed authentication welcome to home page ---after authenticaion from home Username:qian Password:zxc123 User has passed authentication welcome to bbs page ---after authenticaion
10不过这不是我要讲的高潮部分,而是补充前面的前奏
同志们在真正的现实生活中,账号认证方式有多种,现在的认证方式是本地认证,下面才是真正的终极
import time user,passwd = 'qian','zxc123' def auth(auth_type): print("auth func:",auth_type) def outer_wrapper(func): def wrapper(*args,**kwargs): #包装 if auth_type == "local": username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("\033[32;1mUser has passed authentication\033[0m") res = func(*args,**kwargs) print("---after authenticaion") return res else: exit("\033[31;1mInvalid 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") #本地的文件认证 home = wrapper def home(): print("welcome to home page") return "from home" @auth(auth_type ="ldap") #ldap认证 def bbs(): print("welcome to bbs page") index() print(home()) #wrapper() bbs() 结果 auth func: local auth func: ldap welcome to index page Username:qian Password:zxc123 User has passed authentication welcome to home page ---after authenticaion from home #调用方式 home() 就没这个返回值了 搞毛线ldap,不会
这就是我们的终极版本, 运行的具体顺序可以自己调试调试
这个函数的作用分别是:
1.auth(auth_type) 传递装饰器的参数
2.outer_wrapper(func) 把函数当做实参传递进来
3.wrapper(*args,**kwargs) 真正执行装饰的函数
##home()