python装饰器:扩展原来函数功能的一种函数(它返回的是一个函数)。
作用:在不修改原代码的基础上给原函数增加新的功能,一般而言我们原始的函数需要增加一些功能,最直接的方法就是去原代码函数中进行修改,那么如果许多个函数都需要增加某个功能呢?这样就特别浪费时间,so,python的装饰器就这么厉害,接下来我们通过例子来了解python的装饰器。
原始函数(举比较简单的例子):
def
func_test1():
print(
"This is a function named function_test1")
def
func_test2():
print(
"This is a function named function_test2")
突然有一天我们需要在在所有函数增加统计函数的执行时间功能,此时可以写一个装饰器(可以看到该装饰器接收的是一个函数名,返回的也是一个函数):
def
decorator(
func):
def
wrapper():
startime = time.time()
func()
endtime = time.time()
print(func.
__name__ +
" spend time " +
str(endtime-startime))
return wrapper
那么问题来了,增加这个装饰器函数就可以了吗?当然不是,我们需要使用“@”符号来引用它,在所有需要修改的函数之前添加“@装饰器函数名”。
@decorator
def
func_test1():
print(
"This is a function named function_test1")
@decorator
def
func_test2():
print(
"This is a function named function_test2")
func_test1()
func_test2()
执行结果:
PS D:\
python\class\decorator> python .\r2.py
This
is a function named function_test1
func_test1 spend time
0.00029206275939941406
This
is a function named function_test2
func_test2 spend time
0.0
PS D:\
python\class\decorator>
上面的装饰器或许对于初学的你还有些不是很清楚,接下来举个带参数的装饰器或许你会恍然大悟(通过参数对应的输出来理解装饰器):
def
decorator(
func):
def
wrapper(*
args):
startime = time.time()
func(*args)
endtime = time.time()
print(func.
__name__ +
" spend time " +
str(endtime-startime))
return wrapper
@decorator
def
func_test1(
func_arg1):
print(
"This is a function named " + func_arg1)
@decorator
def
func_test2(
func_arg1,
func_arg2):
print(
"This is a function named " + func_arg1)
print(
"This is a function named " + func_arg2)
func_test1(
'function1')
func_test2(
'function1',
'function2')
运行结果:
PS D:\
python\class\decorator> python .\r2.py
This
is a function named function1
func_test1 spend time
0.0
This
is a function named function1
This
is a function named function2
func_test2 spend time
0.0004956722259521484
PS D:\
python\class\decorator>
注意:装饰器嵌套函数使用的是可变参数,为了方式原始函数带有不同个数的参数。
问题:如果存在关键字参数,装饰器如果写呢?同理我们只需要在装饰函数中添加关键字形参(在实际应用中比较少用)。
def
decorator(
func):
def
wrapper(*
args,**
kw):
startime = time.time()
func(*args,**kw)
endtime = time.time()
print(func.
__name__ +
" spend time " +
str(endtime-startime))
return wrapper
@decorator
def
func_test1(
func_arg1):
print(
"This is a function named " + func_arg1)
@decorator
def
func_test2(
func_arg1,
func_arg2):
print(
"This is a function named " + func_arg1)
print(
"This is a function named " + func_arg2)
@decorator
def
func_test3(
func_arg1,
func_arg2,**
kw):
print(
"This is a function named " + func_arg1)
print(
"This is a function named " + func_arg2)
print(
"keyword params " +
str(kw))
func_test1(
'function1')
func_test2(
'function1',
'function2')
func_test3(
'function1',
'function2',
a=
1,
b=
False,
c=
'123')
运行结果:
PS D:\
python\class\decorator> python .\r2.py
This
is a function named function1
func_test1 spend time
0.0004956722259521484
This
is a function named function1
This
is a function named function2
func_test2 spend time
0.0004944801330566406
This
is a function named function1
This
is a function named function2
keyword params {
'a':
1,
'b':
False,
'c':
'123'}
func_test3 spend time
0.0004980564117431641
PS D:\
python\class\decorator>
我们会发现:加上装饰器func_test1.__name__的值是wrapper,帮助信息也变成了wrapper的信息,是因为我们的函数名称传递给装饰器后实质上执行的是wrapper函数,这样就会造成影响了我们的原始代码的结果。
def
decorator(
func):
def
wrapper():
startime = time.time()
func()
endtime = time.time()
print(func.
__name__ +
" spend time " +
str(endtime-startime))
return wrapper
@decorator
def
func_test1():
'''
This function is a test
'''
print(
"This is a function named " + func_test1.
__name__)
func_test1()
help(func_test1)
PS D:\
python\class\decorator> python .\r3.py
This
is a function named
wrapper
func_test1 spend time
0.0005042552947998047
Help on function wrapper
in module __main__:
wrapper()
PS D:\
python\class\decorator>
对于这个影响我们可以通过引入装饰wraps来避免这个问题,我们需要从functiontools这个模块库加载wraps:
import time
from functools
import wraps
def
decorator(
func):
@wraps(func)
def
wrapper():
startime = time.time()
func()
endtime = time.time()
print(func.
__name__ +
" spend time " +
str(endtime-startime))
return wrapper
@decorator
def
func_test1():
'''
This function is a test
'''
print(
"This is a function named " + func_test1.
__name__)
func_test1()
help(func_test1)
PS D:\
python\class\decorator> python .\r3.py
This
is a function named func_test1
func_test1 spend time
0.0
Help on function func_test1
in module __main__:
func_test1()
This function
is a test
PS D:\
python\class\decorator>
可以看出原始函数的帮助信息和名称不变,是因为wraps装饰器参数func接收的是原始函数,它会把原有函数的一系列信息复制到wrapper函数中。