装饰器:
把函数当作参数,返回一个替代版的函数
本质为返回函数的函数
作用:
##在不改变原函数【代码】的基础上,给函数增加功能
示例:
import time ##导入时间模块
def decorator(func): ##装饰器
def wrapper(*args,**kwargs):
print(time.time()) ##打印时间
func(*args,**kwargs) ##执行原函数
return wrapper ##使wrapper函数执行
@decorator ##声明有装饰器
def f1(): ##原函数
print('This is a function')
f1()
运行结果:
在调用原函数后,会先执行装饰器decorator函数,进入装饰器后通过返回值wrapper再执行wrapper函数,打印时间,执行原函数。装饰器是通过把原函数当作参数,通过形参-实参使用的。
【帮助文档写法】【添加装饰器比较两个函数运行时间】:
比较两个连接函数的运行时间【添加装饰器比较】【帮助文档写法】
import random ##导入随机序列
import string ##导入字符
import functools ## functools模块中主要包含了一些函数装饰器和便捷的功能函数
import time ##导入时间
li = [random.choice(string.ascii_letters) for i in range(10)] ##随机选择100个字符
def timec(fun): ##装饰器
@functools.wraps(fun) ##可以保证装饰器不会对被装饰函数造成影响
def wrapper(*args,**kwargs): ##wrapper函数 ##args:元组 kwargs:字典
start_time = time.time() ##开始时间
res = fun(*args,**kwargs) ##运行原函数,并保留结果到res中
end_time = time.time() ##结束时间
print('运行时间为: %.6f' %(end_time - start_time)) ##打印运行时间
return res ##返回值
return wrapper ##进入函数后执行wrapper的指定
@timec
def con_add(): ##生成序列的方法一
"""这是一个con_add函数""" ##说明
s = ''
for i in li:
s += (i + ',')
print(s)
@timec
def join_add(): ##生成序列的方法二
print(','.join(li))
con_add() ##执行方法一
join_add() ##执行方法二
##指定函数的帮助文档,函数名的获取【默认获取的是最先的装饰器的文档和名字】
print(con_add.__doc__) ##打印con_add函数中的说明:"""这是一个con_add函数"""
print(con_add.__name__) ##打印con_add函数的名字:con_add
运行结果:
在上面这个例子中,充分运用了装饰器,使得在不更改原代码的基础上增加了功能。但是对于装饰器中的函数返回值并没有使用。
下面再举一例说明:
【装饰器中函数返回值调用】:
还是查看时间,这次查看一个函数的运行时间
import functools
import time
def add_log(fun): #装饰器
@functools.wraps(fun)
def wrapper(*args,**kwargs): #wrapper函数
start_time = time.time() #开始时间
res = fun(*args,**kwargs) #运行原函数,并保留其结果到res
end_time = time.time() #结束时间
print('[%s] 函数名: %s, 运行时间: %.6f, 运行返回值结果: %d'
%(time.ctime(),fun.__name__,end_time - start_time,res))
return res ##返回值为res
return wrapper
@add_log
def add(x,y):
time.sleep(1)
return x + y
add(5,2)
图示:
通过装饰器中的函数返回值,来得到函数运行的结果,并输出。
【装饰器中有参数时:双层装饰器达到传递参数功能】:
import time
import functools
def log_kind(kind): #外层装饰器
def add_log(fun): #内层装饰器
@functools.wraps(fun) #保证装饰器不会对原函数的一些模块造成影响
def wrapper(*args,**kwargs): #装饰器中执行功能的函数
start_time = time.time() #开始时间
res = fun(*args,**kwargs) #将函数运行结果赋值给res
end_time = time.time() #结束时间
print('<%s>[%s] 函数名: %s, 运行时间: %.6f, 运行返回值结果: %d'
%(kind,time.ctime(),fun.__name__,end_time - start_time,res)) #打印内容
return res #将函数运行结果返回 #这里可以不写,并没有调用该wrapper函数的返回值
return wrapper #使调用wrapper函数
return add_log #使调用add_log函数
@log_kind('debug') #添加装饰器
def add(x,y): #原函数:1秒钟后返回一个加法结果,但是没有输出
time.sleep(1)
return x + y #
add(1,2) #运行原函数
运行结果:
这个例子中,我们主要是要观察lod_kind()装饰器中,我们使用时给其中添加了参数’debug’,而在通常使用的装饰器中是没有添加参数的。那么我们使用多层装饰器来达到传递参数的功能。【装饰器的()中要加入被执行的函数,所以无法直接加入参数】
【多个装饰器】:
def decorator_a(fun): #装饰器一
def inner_a(*args,**kwargs): #装饰器内执行动作的函数
print('Get in inner_a') #打印内容
return fun(*args,**kwargs) #执行原函数,装饰器返回其值
return inner_a #使inner_a函数被执行
def decorator_b(fun): #装饰器二
def inner_b(*args,**kwargs): #装饰器内执行动作的函数
print('Get in inner_b') #打印内容
return fun(*args,**kwargs) #执行原函数,装饰器返回其值
return inner_b #使inner_b函数被执行
@decorator_b #添加装饰器b
@decorator_a #添加装饰器a
def f(x): #原函数
print('Get in f') #打印内容
return x*2 #返回两个参数x
f(1) #执行原函数
运行结果:
先添加了装饰器b,则先打印出了装饰器b的结果。 上述代码中的各返回值都没有去调用,可以省略。
大大的小小阳