(4)python装饰器
【1】前置知识储备
详细参考上一篇博文:https://www.cnblogs.com/gered/p/13954411.html#autoid-1-3-0
【1.1】函数即变量
在数字、字符串变量中,我们之前的数据类型文章中就说了,它是不可以修改的,因为它是放在内存堆中。如果修改就是新赋值,就是在内存堆中重新开辟了一个字符串/数字,然后把变量指向它;
字符串举例:
如果有 x=1,y=x,那么这个时候, x 和 y都是引用指向 1 的内存地址,x 如果修改不影响 y。
那么这个内存中的1什么时候被回收呢? 当该内存存储地址没有被任何变量、函数等引用指向的话,就会随着python默认的刷新检测机制检测发现没有任何引用,就会把它回收掉:
函数同理:
那么同理,函数名也是一个引用指针,指向内存中存储函数体的这一块地址。这个我们从匿名函数形式 就可以比较直观的看出来;
【1.2】高阶函数
(1)把函数名做实参传给另外一个函数的形参(这也就表达了,高阶函数可以在不修改被装饰函数代码的情况下,为其添加功能)
(2)返回值中包含函数名(不修改函数的调用方式的情况下,为其添加功能)
【1.3】嵌套函数
嵌套函数,就是在函数的内部用def 定义另外的函数
【2】装饰器:基本形式(就是高阶函数+嵌套函数)
装饰器:本质上是函数,是用来装饰其他函数的(就是为其他函数添加附加功能)
原则(1):不能修改被装饰的函数的源代码
原则(2):不能修改被装饰的函数的调用方式
即:装饰器对函数来说是完全透明的,就是说函数感知不到装饰器的存在,也就函数的源代码和调用方式都没有被改变
(1)好理解的形式(无参数)
import time def test1(): time.sleep(3) print('in the test1') def test2(): time.sleep(3) print('in the test2') def timer(func): # timer(test1) func=test1 def deco(): start_time=time.time() func() # run test1() stop_time=time.time() print('run the fun used {} second'.format(stop_time-start_time)) return deco test1 = timer(test1) test1()
in the test1
run the fun used 3.0009162425994873 second
~~~实现了不修改函数源代码,也不修改函数调用方式,添加了新功能 输出函数执行使用时间
(2)语法糖:即用 @装饰器名 放到函数定义的上一行(带参数)
不带参数的函数也可以用 这种装饰器
import time def timer(func): def warpper(*args,**kwargs): start_time=time.time() func(*args,**kwargs) stop_time=time.time() print('the func run time is {} '.format(stop_time-start_time)) return warpper
@timer # 这里实现了 test1 = timer(test1) 的功能 def test1(a,b,c): time.sleep(3) print('this is test1!')
print(a,b,c)
test1(1,2,3)
this is test1!
the func run time is 3.000502824783325
(3)返回值的参数
import time user, passwd = 'gg', '123456' def auth(func): def wrapper(*args, **kwargs): username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("\033[32;1m User has passed authentication\033[0m") res = func(*args, **kwargs)
print('函数运行完毕')
return res else: exit("\033[31;1m Invalid Username or Password \033[0m") return wrapper def index(): print("welcome to index page") @auth def home(): print("welcome to home page")
return '我是home函数的返回值' @auth def bbs(): print("welcome to bbs page") index() print(home())
welcome to index page
Username:gg
Password:123456
User has passed authentication
welcome to home page
函数运行完毕
我是home函数的返回值
(4)高潮迭起的装饰器:装饰器本身参数
# 根据装饰器参数,区分函数类别 user, passwd = 'gg', '123456' def auth(auth_type): print("auth func type:",auth_type) def out_wrapper(func): def wrapper(*args, **kwargs): if auth_type == 'bbs': username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("\033[32;1m User has passed authentication\033[0m") res = func(*args, **kwargs) print('函数运行完毕') return res else: exit("\033[31;1m Invalid Username or Password \033[0m") elif auth_type == 'home': print('自己直接访问就可以了啊,不需要做登录验证') else: print('又不是自己家,又不是bbs,滚蛋!') return wrapper return out_wrapper def index(): print("welcome to index page") @auth('home') def home1(): print("welcome to home1 page") return '我是home1函数的返回值' @auth('home') def home2(): print("welcome to home1 page") return '我是home1函数的返回值' @auth('bbs') def bbs1(): print("welcome to bbs page") @auth('bbs') def bbs2(): print("welcome to bbs page") index() home1() bbs1()
auth func type: home
auth func type: home
auth func type: bbs
auth func type: bbs
welcome to index page
自己直接访问就可以了啊,不需要做登录验证
Username:gg
Password:123456
User has passed authentication
welcome to bbs page
函数运行完毕