装饰器:装饰器的本质是闭包
定义:
开放封闭原则:
测试index函数的执行效率
版本一有问题:如果测试别人的代码,必须重新赋值粘贴
def index(): ''' 有很多代码 ''' time.sleep(3) print("欢迎登陆博客园!") import time print(time.time()) # 格林威治时间。 start_time=time.time() index() end_time=time.time()
版本二:解决代码重复使用的问题
def timmer(f): start_time=time.time() f() end_time=time.time() print(f"测试本函数的执行效率{end_time-start_time}") timmer(index) # 版本二还是有问题:原来index函数源码没有变化,给源函数添加了一个新的功能,测试原函数的执行效率的功能 #不满足开放封闭原则,因为原函数的调用方式变了
版本三:不能改变原函数的调用方式------------原生态修饰器
def timmer(f): def inner(): start_time=time.time() f() end_time=time.time() print(f"测试本函数的执行效率{end_time-start_time}") return inner # ret=timmer(index) # inner # ret() # inner() ret=timmer(index) index=timmer(index)
版本四:具体研究
def index(): # 有很多代码 time.sleep(3) print("欢迎登陆博客园!") def timmer(f): # 相当于创建了一个自由变量 f=index # index的内存地址 def inner(): start_time=time.time() f() end_time=time.time() print(f"测试本函数的执行效率{end_time-start_time}") return inner index=timmer(index) index()
版本五--标准装饰器
import time # timmer装饰器写再在最上面 def timmer(f): def inner(): start_time = time.time() f() end_time = time.time() print(f"{end_time - start_time}") return inner @timmer # 等同于index=timmer(index),需要将@装饰器名字放在被装饰的函数前面,因为读到这里的时候,解释器会向下多读一行, def index(): # 很多代码 time.sleep(2) # 模拟网络延迟或者代码效率 print("欢迎登陆博客园首页") index()
版本六--被装饰函数带返回值
import time # timmer装饰器写再在最上面 def timmer(f): def inner(): start_time = time.time() r=f() # 真正的index执行者 end_time = time.time() print(f"{end_time - start_time}") return r return inner @timmer # 等同于index=timmer(index),需要将@装饰器名字放在被装饰的函数前面,因为读到这里的时候,解释器会向下多读一行, def index(): # 很多代码 time.sleep(2) # 模拟网络延迟或者代码效率 print("欢迎登陆博客园首页") return 666 # 加上装饰器不应该改变原函数的返回值,所以666应该返回给我下面的ret, # 但是下面的ret实际接受的是inner函数的返回值,而666返回给的是装饰器里面的f() # 也就是r,我们现在要解决的问题就是将r给inner的返回值 ret=index() print(ret)
版本七--被装饰函数带参数(最标准的)
import time # timmer装饰器写再在最上面 def timmer(f): def inner(*args,**kwargs): # 函数的调用:*聚合args=('taibai',18) start_time = time.time() r=f(*args,**kwargs) # 真正的index执行者 # 函数的执行:*打散:f(iterable)-->f(*('taibai',18))-->f('taibai',18) end_time = time.time() print(f"{end_time - start_time}") return r return inner @timmer # 等同于index=timmer(index),需要将@装饰器名字放在被装饰的函数前面,因为读到这里的时候,解释器会向下多读一行, def index(name): # 很多代码 time.sleep(2) # 模拟网络延迟或者代码效率 print(f"欢迎{name}登陆博客园首页") index("纳钦") # inner() ------------------------------------------- def dariy(name,age): time.sleep(1) print(f"欢迎{age}岁的{name}登陆日记页面") dariy('taibai',18)
标准版的装饰器:
def wrapper(f): def inner(*args,**kwargs): """添加额外的功能,执行被装饰函数之前的操作""" ret=f(*args,**kwargs) """添加额外的功能,执行被装饰函数之后的操作""" return inner
装饰器的应用
登录认证
def login(): print("请完成登录功能") def register(): print('请完成注册功能') status_dic={ 'username':None, 'status':False } def auth(f): ''' 你的装饰器完成:访问被装饰函数之前,写一个三次认证的功能 登陆成功,让其访问被装饰的函数,登录没有成功,不让访问。 :param f: :return: ''' def inner(*args,**kwargs): '''访问函数之前的操作。功能''' if status_dic['status']: ret=f(*args,**kwargs) return ret else: username=input("请输入用户名") password=input("请输入密码") if username=='taibai' and password=='123': print("登陆成功") status_dic['username']=username status_dic['status']=True ret = f(*args, **kwargs) return ret else: print("登陆失败") return inner @auth # article=auth(article) def article(): print('欢迎访问文章页面') @auth def comment(): print('欢迎访问评论页面') @auth def dariy(): print('欢迎访问日记页面') article() # inner comment() dariy()