Python的装饰器decorator本质上是一个高阶函数,它接收一个函数作为参数,然后返回一个新的函数,可以让该函数在不改动源代码的情况下增加其他新功能。
python通过一个语法糖@
符号来使用decorator,这样可以避免编写f = decorate(f)
这样形式的代码。所谓的语法糖便是你不使用也可以完成任务,但是使用它可以让你的代码更简洁。
对于装饰器,需要记住的就是
@decorate
def f():
pass
其中,
@decorate 等价于 f = decorate(f)
示例:
import time
def performance(f):
def fn(*args, **kw):
t1 = time.time() #unix时间戳
r = f(*args, **kw)
t2 = time.time()
print 'call %s() in %f s' % (f.__name__, t2 - t1)
return r
return fn
@performance
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
执行结果:
call factorial() in 0.002750 s
3628800
@performance
可以打印出factorial()
函数调用的时间。
利用python的*args
和**kw
,可以让@performance
自适应任何参数定义的函数,保证任意个数的参数总是能正常调用。
@performance
完全等价于 factorial = performance(factorial)
。
对于performance()
函数,形成一个闭包。程序首先调用performance(factorial)
,得到的返回结果赋值给了factorial
,这样factorial
就变成了指向函数fn()
的指针,经过装饰后的factorial()
,其实是调用fn()
。
示例:
import time
def performance(unit):
def perf_decorator(f):
def wrapper(*args, **kw):
t1 = time.time()
r = f(*args, **kw)
t2 = time.time()
t = (t2 - t1) * 1000 if unit =='ms' else (t2 - t1)
print 'call %s() in %f %s' %(f.__name__, t, unit)
return r
return wrapper
return perf_decorator
@performance('ms')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
执行结果:
call factorial() in 2.448082 ms
3628800
@performance('ms')
完全等价于 factorial = performance('ms')(factorial)
。
而factorial = performance('ms')(factorial)
展开一下就是:
perf_decorator = performance('ms')
factorial = perf_decorator(factorial)
即
perf_decorator = performance('ms')
@perf_decorator
def factorial():
pass
所以,带参数的performance()
函数首先返回一个decorator
函数,再让这个decorator
函数接收factorial
并返回新函数。
对于performance()
函数,形成一个闭包;对于perf_decorator()
函数,也形成一个闭包。程序首先调用performance('ms')
,返回perf_decorator
,再将perf_decorator(factorial)
得到的返回结果赋值给了factorial
,这样factorial
就变成了指向函数wrapper()
的指针,经过装饰后的factorial()
,其实是调用wrapper()
。
此外,python还有内置函数property()
,用作装饰器时可以很方便的创建只读属性。
python内置函数:https://docs.python.org/zh-cn/3/library/functions.html