python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。
这个函数的特殊之处在于它的返回值也是一个函数,这个函数是内嵌“原“”函数的函数。
之前拓展函数的做法是侵入原函数进行拓展修改,例如:
原始函数:
import
time
def
f():
print
(
"hello"
)
time.sleep(
1
)
print
(
"python"
)
begintime = time.time()
print("hello")
time.sleep(1)
print("python")
endtime = time.time()
totaltime = (endtime - begintime )*1000
print("time is %d ms" %totaltime )
使用闭包函数的用法如下:
import time
def test(func):
begintime = time.time()
f()
endtime = time.time()
totaltime = (endtime - begintime) * 1000
print("执行时间:%d ms"%tataltime)
def f():
print("hello")
time.sleep(1)
print("python")
if __name == "__main__":
test(f)
这种方式的缺点是:但是想要拓展这一千万个函数功能,就是要执行一千万次test()函数。
使用装饰器来实现如下:
import time
def test(f):
def func():
begintime = time.time()
f()
endtime = time.time()
totaltime = (endtime-begintime) * 1000
print("执行时间:%d ms"%tataltime)
return func
@test
def f():
print("hello")
time.sleep(1)
print("python")
if __name == "__main__":
f()
这里的test函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数f()就在返回函数func()的内部执行。然后在函数f()前面加上@test,
f()函数就相当于被注入了计时功能,现在只要调用f(),它就已经变身为“新的功能更多”的函数了(不需要重复执行原函数)。
扩展1:带有固定参数的装饰器
import time
def test(f):
def func(a,b):
begintime = time.time()
f(a,b)
endtime = time.time()
totaltime = (endtime-begintime) * 1000
print("执行时间:%d ms"%tataltime)
return func
@test
def f(a,b):
print("hello")
time.sleep(1)
print("python")
time.sleep(1)
print(a+b)
if __name == "__main__":
f(3,4)
扩展2:无固定参数的装饰器:
import time
def test(f):
def func(*args,**kwargs):
begintime = time.time()
f(*args,**kwargs)
endtime = time.time()
totaltime = (endtime-begintime) * 1000
print("执行时间:%d ms"%tataltime)
return func
@test
def f(a,b):
print("hello")
time.sleep(1)
print("python")
time.sleep(1)
print(a+b)
@test
def f2(a,b,c):
print("hello")
time.sleep(1)
print("python")
time.sleep(1)
print(a+b+c)
if __name == "__main__":
f(3,4)
f2(5,6,7)
扩展3:使用多个装饰器装饰一个函数
import time
def test1(f):
def func(*args,**kwargs):
print("test1")
begintime = time.time()
f(*args,**kwargs)
endtime = time.time()
totaltime = (endtime - begintime) * 1000
print("执行时间:%d ms"%tataltime)
print("test1 end")
return func
def test2(f):
def func(*args,**kwargs)
print("test2 begin")
f(*args,**kwargs)
print("test2 end")
return func
@test1
@test2
def f(a,b):
print("hello")
time.sleep(1)
print("python")
time.sleep(1)
print(a+b+c)
if __name__ == "__main__":
f(3,4)
执行结果:
test1
test2 begin
hello
python
7
test2 end
执行时间:%d ms"%tataltime
test1 end
装饰器调用顺序
装饰器是可以叠加使用的,那么使用装饰器以后代码是啥顺序呢?
对于Python中的”@”语法糖,装饰器的调用顺序与使用 @ 语法糖声明的顺序相反。
在这个例子中,”f(3, 4) = test1(test2(f(3, 4)))”。
Python内置装饰器
在Python中有三个内置的装饰器,都是跟class相关的:staticmethod、classmethod 和property。
- staticmethod 是类静态方法,其跟成员方法的区别是没有 self 参数,并且可以在类不进行实例化的情况下调用
- classmethod 与成员方法的区别在于所接收的第一个参数不是 self (类实例的指针),而是cls(当前类的具体类型)
- property 是属性的意思,表示可以通过通过类实例直接访问的信息