装饰的工具python
必需要遵循的原则:“开放封闭”闭包
开放:对源函数功能的添加是开放的app
封闭:对源函数功能修改是封闭的函数
在不修改被装饰对象源代码和调用方式的前提下,增长新功能工具
必须遵循的原则:url
一、不修改被装饰对象的源代码code
二、不修改被装饰对象的调用方式对象
解决代码冗余问题,提升代码可扩展性blog
编写装饰器经过闭包函数实现ip
装饰器推导过程
# # 装饰器推导过程 def move(): '''下载电影的源函数''' print('开始下载') time.sleep(2) print('下载完成') def fun(index): def down(): star_time = time.time() index() # 将被装饰对象move赋值给index执行 end_time = time.time() print(f'总耗时{end_time - star_time}') return down fun(move)()
# 有返回值时 def move(): '''下载电影的源函数''' print('开始下载') time.sleep(2) print('下载完成') return '明日之巅.mp4' def fun(index): def down(): star_time = time.time() res = index() # 将index执行结果赋值给res # print(res) end_time = time.time() print(f'总耗时{end_time - star_time}') return res # 将index返回值返回出来 # print(down()) return down move = fun(move) # 将调用方式改为被装饰对象 move()
# 源函数有参数时 def move(url): '''下载电影的源函数''' print(f'{url}开始下载') time.sleep(2) print('下载完成') return '明日之巅.mp4' def wrapper(func): def inner(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) end_time = time.time() print(f'总耗时:{end_time - start_time}') return res return inner move = wrapper(move) move(('https://www.cnblogs.com'))
装饰器最终模板
def wrapper(func): def inner(*args, **kwargs): # 调用前增长新功能 res = func(*args, **kwargs) # 调用被装饰对象,接收返回值 # 调用后增长的新功能 return res # 接收被装饰对象的返回值 return inner
一、装饰器的语法糖是属于装饰器的
二、用@+装饰器名,在被装饰对象开头
三、在使用装饰器语法糖时,装饰器必须定义在被装饰对象之上
# 增长统计代码运行时间的装饰器 def wrapper(func): def inner(*args,**kwargs): start_time = time.time() res = func(*args,**kwargs) end_time = time.time() print(end_time-start_time) return res return inner # 使用语法糖 @wrapper def movie(): print("开始下载") time.sleep(2) print('下载结束') # 不使用语法糖调用增长新功能后的函数 # movie = wrapper(movie) # movie() # 使用语法糖后可直接调用 movie()
在同一个被装饰对象中,添加多个装饰器,并执行
每个新功能都写一个新的装饰器,不然会致使代码冗余,结构不清晰,可扩展性差
@装饰器1 @装饰器2 @装饰器3 def 被装饰对象(): pass
注意:在调用被装饰对象时,才会执行添加的新功能
叠加装饰器装饰顺序,执行顺序:
装饰的顺序:由下往上装饰
执行的顺序:由上往下执行
注意:
一、装饰器内函数inner中出现任何判断,最后都要返回“调用后的被装饰对象”func(*args,**kwargs)
二、被装饰对象在调用时,若是还有其余装饰器,会先执行其余装饰器中的inner
def wrapper1(func1): def inner1(*args, **kwargs): print("1————start") res = func1(*args, **kwargs) print("1————end") return res return inner1 def wrapper2(func2): def inner2(*args, **kwargs): print("2————start") res = func2(*args, **kwargs) print("2————end") return res return inner2 def wrapper3(func3): def inner3(*args, **kwargs): print("3————start") res = func3(*args, **kwargs) print("3————end") return res return inner3 @wrapper1 @wrapper2 @wrapper3 def index(): print("index") index() >>> # 执行顺序:由上而下 # 装饰顺序:由下而上 1————start 2————start 3————start index 3————end 2————end 1————end
无参装饰器:装饰在被装饰对象时,没有传参数的装饰器
# 如下是无参装饰器 @wrapper1 @wrapper2 @wrapper3
有参装饰器:在某些时候咱们须要给用户的权限进行分类
# 如下是有参装饰器 @wrapper1(参数1) @wrapper2(参数2) @wrapper3(参数3)
若是咱们想提供多种不一样的认证方式以供选择 , 函数inner须要一个driver参数,而函数wrapper与inner的参数都有其特定的功能,不能用来接受其余类别的参数,能够在wrapper的外部再包一层函数user_auth,用来专门接受额外的参数,这样便保证了在user_auth函数内不管多少层均可以引用到
# 给用户的权限进行分类 def user_auth(driver): def wrapper(func): def inner(*args, **kwargs): if driver == "svip": # 加入超级会员的功能 res = func(*args, **kwargs) return res elif driver == "vip": # 加入会员的功能 res = func(*args, **kwargs) return res else: # 加入普通用户的功能 res = func(*args, **kwargs) return res return inner return wrapper @user_auth(driver='svip') def user_power(): pass user_power()
是一个修复工具,修复的是被装饰对象的空间
一、先从functools中调用wraps >>> from functools import wraps
二、装饰器在定义内层函数前加@wraps(func) 修更名称空间:将inner >>> func
三、inner前加@wraps(func)是将inner名称空间修改到func,若是不用@wraps(func)打印注释本质打印的是inner的注释,加上@wraps(func)修复被装饰对象的空间,打印注释就会打印被装饰对象的注释
# 函数对象.__doc__ 是查看内部的注释 from functools import wraps # 从functools中调用wraps模块 def wrapper(func): @wraps(func) # 修更名称空间,inner >>> func def inner(*args,**kwargs): ''' 装饰器的注释 ''' # 调用被装饰对象前加的功能 res = func(*args,**kwargs) # 调用被装饰对象前加的功能 return res return inner @wrapper def index(): ''' 被装饰对象index的注释 :return: ''' pass print(index.__doc__) # 加上@wraps(func) >>> 被装饰对象index的注释 :return: # 不加@wraps(func) >>> 装饰器的注释