转自:https://blog.csdn.net/weixin_41179709/article/details/81879601
装饰器介绍
装饰器就是对被装饰的对象(函数、类)进行重构的,其可以在不改变原来对象的情况下调用对象时执行重构后的行为
- 解决问题:在函数执行之前和执行之后添加功能,调用函数的方式改变了
- 不改变原有函数的调用方法:函数里面嵌套函数,并且返回嵌套的函数
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ##引题:当登陆某系统时常常会有欢迎语,但修改时将在登陆函数中修改,可能会出现问题,所以避免直接侵入原函数修改。 def login(): print("中秋快乐") print("login....") print("欢迎您下次光临....") login()
##为了避免在大的函数块中操作,将欢迎语独立出来,另建函数。 def desc(fun): def add_info(): print("中秋快乐") fun() print("欢迎您下次光临") return add_info def login(): print("login....") login = desc(login) login()
|
装饰器语法糖
在Python中,可以使用”@”语法糖来精简装饰器的代码,把 decorator 置于函数的定义处,免去给函数重新赋值(即function = decorator(funtion))
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import functools #functools 标准库 import time #time 时间函数
def add_log(fun): @functools.wraps(fun) #不用此模块add(x,y)函数的__name__,__doc__都会丢失 def wrapper(*args,**kwargs): #*args为元组 **kwargs为字典 start_time = time.time() res = fun(*args,**kwargs) end_time = time.time() print("[%s] 函数名:%s, 运行时间 :%.5f ,运行返回值:% d" %(time.ctime(),fun.__name__,end_time- start_time,res)) return res #返回值为所要装饰的函数 return wrapper #返回值为所要修饰函数所添加的模块 @add_log ##调用语法糖 def add(x,y): time.sleep(0.1) return x+y print(add(1,2))
|
装饰的函数有返回值
解决办法:给返回值赋值
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| def timeit(fun): def wrapper(*args,**kwargs): #接收可变参数和关键字参数 #args:元组 kwargs:字典 args=(5,) #原函数执行之前 start_time = time.time() #执行函数 res = fun(*args,**kwargs) #args解包 #执行函数 end_time = time.time() print("运行时间为:%.6f" % (end_time - start_time)) return res return wrapper
@timeit def list_create(n): return(i*2 for i in range(n)])
@timeit def map_create(n): return(list(map(lambda x:x*2,range(n))))
list_create(5) map_create(5) print(list_create(100)) ##wrapper(100)
|
保留被装饰的函数的函数名和帮助文档信息
解决办法:导入functools标准库,使用functools.wraps函数,保留被装饰的函数的函数名和帮助文档信息。
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import functools def timeit(fun): """这是一个装饰器timeit""" @functools.wraps(fun) ##内置装饰器 可以保留被装饰的函数的函数名和帮助文档信息 def wrapper(*args,**kwargs): #接收可变参数和关键字参数 """这是一个wrapper函数""" #args:元组 kwargs:字典 args=(5,) #原函数执行之前 start_time = time.time() #执行函数 res = fun(*args,**kwargs) #args解包 #执行函数 end_time = time.time() print("运行时间为:%.6f" % (end_time - start_time)) return res return wrapper @timeit def fun(): print("hello") print(fun_list.__name__) print(fun_list.__doc__)
|
装饰器中不同条件下执行不同的函数
用实例说明:需求: 用户来CSDN登陆验证的装饰器is_login
- 如果用户登陆成功, 则执行被装饰的函数;
- 如果用户登陆不成功, 则执行登陆函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import functools login_users = ['admin', 'root']
def is_login(fun): # fun: writeBlog @functools.wraps(fun) def wrapper(*args, **kwargs): # name="admin" # kwargs={"name":"admin"} # 判断写博客的这个用户是否登陆成功; if kwargs.get("name") in login_users: res = fun(*args, **kwargs) return res else: res=login() return res
return wrapper
# 必须登陆成功 @is_login # writeBlog = is_login(writeBlog) def writeBlog(name): return "编写博客"
def login(): return "登陆。。。。"
# 是否登陆成功都可以执行代码 def news(): print("新闻......")
print(writeBlog(name="admin"))
|
多个装饰器
若有两个装饰器,从上到下调用装饰器,wrapper内容也是为由上向下执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def makebold(fun): print("bold1") def wrapper1(*args, **kwargs): print("bold2") return fun(*args, **kwargs) # wrapper return wrapper1 def makei(fun): # fun=login print("i1") def wrapper(*args, **kwargs): print("i2") return fun(*args, **kwargs) return wrapper # 当有多个装饰器时,从上到下调用装饰器 # 真实wrapper内容执行是从上到下执行 @makebold #login = makebold(login) #login为wrapper1 @makei #login = makei(login) #login为wrapper def login(): return "登陆" print(login())
|
带有参数的装饰器
创建装饰器, 要求如下:
- 创建add_log装饰器, 被装饰的函数打印日志信息;
- 日志格式为:
[字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| # 创建装饰器, 要求如下: # 1. 创建add_log装饰器, 被装饰的函数打印日志信息; # 2. 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx
import functools import time
# format def log(kind): # kind="debug" def add_log(fun): @functools.wraps(fun) def wrapper(*args, **kwargs): start_time = time.time() res = fun(*args, **kwargs) end_time = time.time() print("<%s> [%s] 函数名: %s, 运行时间:%.5f, 运行返回值结果:%d" %(kind, time.ctime(), fun.__name__, end_time-start_time, res ) ) return res return wrapper return add_log @log("debug") # log("debug")==> 返回值是add_log # add=add_log(add) def add(x,y): time.sleep(0.1) return x+y print(add(14214124124,1241231231313)) # wrapper(14214124124,1241231231313)
|