装饰器
一、开放封闭原则
开放封闭原则:在不修改源代码与原函数的调用方式的情况下,为函数添加新功能, 对修改封闭,对扩展开放
二、什么是装饰器
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
三、装饰器的基本框架
# @outer语法来调用outer,规定传入被装饰的函数对象,所以参数固定为一个,接受被装饰的函数对象 from functools import wraps def outer(func): @wraps(func) # 系统的wraps带参装饰器:改变inner的假指向,本质外界使用的还是inner,但是打印显示的是wraps中的函数 # 不能确定被装饰的函数的参数:来者不拒,用可边长来接受 def inner(*args, **kwargs): print('执行被装饰函数之前 你可以执行的操作') res = func(*args, **kwargs) # 解压带给原功能 print('执行被装饰函数之后 你可以执行的操作') return res return inner # 使用装饰器(outer),得到新功能(inner) # 用被装饰的函数名去接受装饰器的执行结果,调用装饰器时传入被装饰的函数对象 @outer # fn = outer(fn) = inner def fn(): pass # 表面感觉调用的是原函数,本质调用的是闭包(inner),使用fn调用和fn定义及inner需要参数统一 fn()
四、装饰器的使用
import time def timmer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper @timmer def foo(): time.sleep(3) print('from foo') foo()
五、带参装饰器
# 通常,装饰器为被装饰的函数添加新功能,需要外界的参数 # uter参数固定一个,就是func # inner参数固定同被装饰的函数,也不能添加新参数 # 可以借助函数的嵌套定义,外层给内层传参 def wrap(info): def outer(func): # info = 0 def inner(*args, **kwargs): print('新:拓展的新功能,可能也需要外界的参数%s' % info) res = func(*args, **kwargs) return res return inner return outer @wrap('外部参数') #fn = wrap(info): fn = inner函数的内存地址 def fn(): pass
六、叠加多个装饰器
def outer(func): def inner(*args, **kwargs): res = func(*args, **kwargs) return res return inner def check_user(func): def inner(*args, **kwargs): # 账号的验证功能 user = args[0] # type: str if not (user.isalpha() and len(user) >= 3): print('账号不合法') return False res = func(*args, **kwargs) return res return inner def check_pwd(func): def inner(*args, **kwargs): pwd = args[1] if len(pwd) < 3: print('密码不合法') return False res = func(*args, **kwargs) return res return inner def format_return(func): def inner(*args, **kwargs): res = func(*args, **kwargs) if res: return '登录成功' return '登录失败' return inner # 登录的原功能 @format_return @check_user @check_pwd def login(user, pwd): if user == 'owen' and pwd == '123': return True return False user = input('user: ') pwd = input('pwd: ') res = login(user, pwd) print(res) # 执行过程:调用login => 进入第一个装饰器(format_return)的inner => 进入第二个装饰器(check_user)的inner => 进入第三个装饰器(check_pwd)的inner => 开始返回,从第三个返回到第二个再返回到第一个,最后返回到外界调用的位置
七、登录认证装饰器
def login_auth(func): from core import src def inner(*args, **kwargs): if src.user_info['name']: print('已登录!') res = func(*args, **kwargs) return res else: src.login() return inner
八、装饰器类
import time class A: func = None # 原本的功能 def __init__(self, func): """ 实例化对象 调用 :param func: """ self.func = func # 扩展功能 def __call__(self, *args, **kwargs): """ 实例化对象() 调用 :param args: :param kwargs: :return: """ _start = time.time() res = self.func(*args, **kwargs) _end = time.time() print("函数调用时间: ", _end - _start) return res @A def add(a, b): time.sleep(1) return a + b print(add(1, 3))