装饰器
(1)介绍
装饰器: 本质就是函数,其目的为其他函数添加功能
原则:(1)不修改被装饰函数的源代码(开放封闭原则)
(2)为被装饰函数添加新功能后,不修改被修饰函数的调用方式
组成:高阶函数、嵌套函数、闭包
(2)组成
高阶函数定义:
1.函数接受的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
1 #仅仅使用高阶函数实现函数增加功能 2 import time#导入时间模块 3 def use_1():#原函数 4 time.sleep(3) 5 print("hello") 6 def fo(func):#高阶函数 7 start_time = time.time() 8 func()#当传入的参数为函数名时,此时便会执行该函数 9 end_time = time.time() 10 print("函数运行的时间是%s"%(end_time-start_time))#添加时间计算功能 11 return func 12 use_1 = fo(use_1)#函数的返回值是一个函数名,可以用原变量接受 13 use_1()#在此基础上,可以以原来调用方式调用该函数 14 #打印结果 15 #hello 16 #函数运行的时间是3.000171661376953 17 #hello
由上面函数可知,当只使用高阶函数来为目标函数增加功能时,虽然没有改变原函数的源代码跟执行方式,但不可避免的是函数会执行第二次
嵌套函数:在函数内定义新函数,函数内变量查找遵循L(local)、E(enclosed)、G(global)、B(built)
1 # def qt(func):# 2 # def inner(): 3 # def oc(): 4 # print(func)#变量查找遵循LEGB原则 5 # oc() 6 # inner() 7 # qt("hello")#将hello赋值给参数func
闭包:
如果在一个内部函数里:us(y)就是这个内部函数,
对在外部作用域(但不是在全局作用域)的变量进行引用:x就是被引用的变量,x在外部作用域occ里面,但不在全局作用域里,
则这个内部函数us就是一个闭包。
1 def occ(x): 2 def us(y):#us是闭包 3 print( x + y )#对外部作用域变量x进行引用 4 return us 5 aa = occ(6) 6 aa(4)#
(3)装饰器
注意:@为python内置方法,等价于目标函数名=装饰器函数名(目标函数名),装饰器函数写好,哪个函数要调用直接在其上部写@装饰器名字即可
1 import time 2 def abc(func): 3 def ooo(*args,**kwargs): 4 start_time = time.time() 5 res = func(*args,**kwargs) 6 end_time = time.time() 7 print("函数运行时间为%s"%(end_time-start_time)) 8 return res 9 return ooo 10 @abc#@为python内置方法,等价于aaa=abc(aaa),装饰器函数写好,哪个函数要调用直接在其上部写@装饰器名字即可 11 def aaa(*args,**kwargs): 12 time.sleep(2) 13 print("运行函数了!") 14 print("函数运行结束了!") 15 return "这是aaa的返回值" 16 ccc = aaa()#注意,此时的ccc接受到的是ooo()函数的返回值,并非aaa()的返回值 17 print(ccc)
例子:
不含参数的装饰器
1 use_list = [{"name":"tom","passwd":“123”}, 2 {"name":"eric","passwd":“123”}] 3 use_time = {"name":None,"log":False} 4 5 def ente(func): 6 # use_name = input("请输入用户名:").strip() 7 # use_passwd = input("请输入密码:").strip() 8 def en(*args,**kwargs): 9 if use_time["name"] and use_time["log"]: 10 res = func(*args,**kwargs) 11 return res 12 use_name = input("请输入用户名:").strip() 13 use_passwd = input("请输入密码:").strip() 14 for i in use_list: 15 if use_name == i["name"] and use_passwd == i["passwd"]: 16 use_time["name"] = use_name 17 use_time["passwd"] = use_passwd 18 res = func(*args,**kwargs) 19 return res 20 else: 21 print("用户名或密码错误!") 22 return en 23 @ente 24 def home(): 25 print("欢迎来到京东主页!") 26 @ente 27 def shopping_list(): 28 print("欢迎来到shoping_list!") 29 @ente 30 def shoping_car(): 31 print("欢迎来到shoping_car!") 32 home() 33 shopping_list()
含参数的装饰器
1 use_list = [{"name":"tom","passwd":"123"}, 2 {"name":"eric","passwd":"123"}] 3 use_time = {"name":None,"log":False} 4 def firt(ente_1 = "test") 5 def ente(func): 6 # use_name = input("请输入用户名:").strip() 7 # use_passwd = input("请输入密码:").strip() 8 def en(*args,**kwargs): 9 if use_time["name"] and use_time["log"]: 10 res = func(*args,**kwargs) 11 return res 12 use_name = input("请输入用户名:").strip() 13 use_passwd = input("请输入密码:").strip() 14 for i in use_list: 15 print(i["name"],i["passwd"]) 16 if use_name == i["name"] and use_passwd == i["passwd"]: 17 use_time["name"] = use_name 18 use_time["log"] = True 19 res = func(*args,**kwargs) 20 return res 21 else: 22 print("用户名或密码错误!") 23 return en 24 return ente 25 @firt(ente_1 = "test")#相当于运行firt函数,返回entc函数名,结果等价于@ente,好处是最外层传入了一个参数,内层的闭包函数可以直接引用 26 def home(): 27 print("欢迎来到京东主页!") 28 @firt(ente_1 = "test") 29 def shopping_list(): 30 print("欢迎来到shoping_list!") 31 @firt(ente_1 = "test") 32 def shoping_car(): 33 print("欢迎来到shoping_car!") 34 home() 35 shopping_list()