装饰器
1.什么是装饰器
装饰器本质是函数, 其功能是, 装饰其他函数, 为其他函数添加附加功能
2. 应用场景
若我们的程序已经上线, 这时我们想为其添加新功能,原本是要修改源代码, 但是这有一定的风险,
这时我们可以编写装饰器(新功能函数),为其需要添加新功能的部分修饰
3 装饰器原则
3.1 不能修改被装饰的函数的源代码
3.2 不能修改被装饰的函数的调用方式
3.3 装饰器被装饰的函数来说是透明的
4. 实现装饰器的知识储备:
4.1 函数即“变量”
4.2 高阶函数 (什么是高阶函数)
a. 把一个函数名 当作实参传递给另外一函数(在不修改被装饰的源代码的情况下,添加新功能)
b. 返回值中包含 函数名 (不修改函数的调用方式)
4.3 嵌套函数 (什么是嵌套函数)
在一个函数体内,用def声明另外一个函数
# 嵌套函数 def foo(): print("in the foo") def bar(): print(" in the bar") bar() #bar 不能在外部调用, 因为它相当于一个局部变量 foo() #下面是函数的调用,不是嵌套 def test1(): test2() test1()
5 装饰器示例
5.1 示例1
import time def timmer(func): #test1 作为实参传入 timmer(test1) func=test1 def deco(): start_time=time.time() time.sleep(1) func() #run test1() stop_time=time.time() print("the run time is %s "%(stop_time-start_time)) return deco @timmer #test1=timmer(test1) def test1(): print("in the test1") #可以用Python 语法糖@加在需要被装饰的函数钱 #test1=timmer(test1) #timmer(test1)结果是其函数体-->return deco-->返回deco的内存地址 print(test1) #打印test1即 deco 的内存地址 test1()
先写一个高阶函数实现了“在不修改被装饰的源代码的情况下,添加新功能” ----把test1 这个函数名作为实参传入timmer这个函数
为了不改变其调用方式,我们又利用了嵌套函数,让其返回函数名 warrper
5.2 示例2 ---有参函数装饰器
import time def timmer(func): # func=test2 def deco(args): #增加text2(name)参数args start_time = time.time() time.sleep(3) func(args) #执行args stop_time = time.time() print("the func run time is %s"%(stop_time-start_time)) return deco #返回deco的内存地址 @timmer def test2(name): print("in the test2:",name) test2('frank') # test2() = deco(),要想让test2()加参数,则需要给deco加参数
5.3 示例3 ---装饰任意函数的装饰器
import time def timmer(func): def deco(*args,**kwargs): #如果有增加参数,如果没有不加 start_time = time.time() time.sleep(3) func(*args,**kwargs) #执行参数,如果有的话 stop_time = time.time() print("the func run time is %s"%(stop_time-start_time)) return deco #返回deco的内存地址 @timmer def test2(name): print("in the test2:",name) @timmer def test1(): print("in the test1") test2('frank')# test2() = deco(),要想让test2()加参数,则需要给deco加参数 test1()
5.4 示例4---终极版---装饰器也带有参数
#!C:\Program Files\Python35/bin # -*- conding: utf-8 -*- #author: Frank def auth(auth_type): #吸收第一层参数,装饰器的参数 #print("auth func",auth_type) def out_warppage(func): #吸收第二层参数,将函数传入 func=home def warppage(*args,**kwargs): if auth_type == "local": user,pwd='frank','123' username = input("Username is :") password = input("Password is :") if username == user and password == pwd: print("\033[32;1myou had login succesfull\033[0m") res = func(*args,**kwargs) #run home(),index(),bbs() return res else: exit("\033[31;1m Invaild user/password\033[0m") else: print("Ldap 不会") return warppage return out_warppage def index(): print("welcom to index page") @auth(auth_type="local") #当装饰器也带有参数时,我们需要在嵌套一层, #装饰器的参数传给顶层函数作为实参 def home(): print("welcom to home page") return "from home" @auth(auth_type="ldap") def bbs(): print("weblcom to bbs") index() bbs() home() #home=warapper
当语法糖也带有参数时, 我们需要在嵌套一层
a. 语法糖的参数传入顶层函数,加载以何种方式装饰(“local” or "ldap")
b.被修饰的函数当作实参被传入第二层
c. 在a.b 两步都准备好之后,开始执行函数,这时a.b都加载进来了,便可以自如的做判断