装饰器本质上是一个Python函数或类,可以让其他函数或类在不需要做任务代码修改的前提下增加额外的功能,装饰器的返回值也是一个函数或类对象
。
1.插入日志
2.性能测试
3.事务处理
4.缓存机制
5.权限校验
6.路由分发等
需求:性能测试,记录每个函数处理的时间
import time
def process_time(func):
"""写一个处理时间的函数:"""
# 记录处理func()函数前的时间
start_time = time.time()
func()
# 记录处理func()函数后的书简
end_time = time.time()
# 做差值, 就是这个func()函数的处理时间
result = end_time - start_time
print 'time is %s s' % result
def func():
"""简单的函数"""
time.sleep(5)
print '___1.我先执行__'
# 将func 函数当作参数进行传入到process_time函数中, 进行处理, 获取func这个函数的处理时间
process_time(func)
# 输出结果如下:
___1.我先执行__
time is 5.00099992752 s
以上栗子,可以实现我们的需求,可是如果有func2(), func3()很多函数都需要此功能,我们还需要多次调用process_time()函数,传入不同的参数,这样做肯定不符合Python的优雅,下面开始进入简单装饰器的使用
。
import time
def decorator(func):
"""装饰器函数"""
def wrapper():
start_time = time.time()
func()
end_time = time.time()
result = end_time - start_time
print 'time is %s s' % result
return result
return wrapper
@decorator
def func():
"""简单的函数"""
time.sleep(2)
print '___1.我先执行__'
print func()
# 输出结果如下:
___1.我先执行__
time is 2.0 s
2.0
注意:@符号,在Python中叫语法糖,使用语法糖,同等于func = decorator(func)的使用
带有参数的装饰器
:
import time
def decorator(func):
"""装饰器函数, 带有参数"""
def wrapper(*args): # 注意有参数时, 需要传递*args, 参数
start_time = time.time()
ret_add = func(*args) # 同理
end_time = time.time()
result = end_time - start_time
print 'time is %s s' % result
return ret_add # 接收的是func(x, y) 函数的返回值, 结果为5
return wrapper
@decorator
def func(x, y):
"""该函数有2个参数"""
time.sleep(2)
print '___1.我先执行__'
return x + y
print func(2, 3)
# 输出结果如下:
___1.我先执行__
time is 2.0 s
5
带有不定长参数的装饰器
:
import time
def decorator(func):
"""装饰器函数, 带有参数"""
def wrapper(*args, **kwargs): # 注意传入不定长参数时, 需要加**kwargs
start_time = time.time()
ret_add = func(*args, **kwargs) # 同理
end_time = time.time()
result = end_time - start_time
print 'time is %s s' % result
return ret_add # 接收的是func(x, y, 2) 函数的返回值, 结果为 25
return wrapper
@decorator
def func(x, y, z):
"""该函数有2个参数"""
time.sleep(2)
print '___1.我先执行__'
return x + y + z
print func(2, 3, z=20)
# 输出结果如下:
___1.我先执行__
time is 2.0 s
25
多个装饰器
:
import time
def decorator1(func):
"""装饰器函数1, 带有参数"""
print '___进入装饰器1___'
def wrapper(*args, **kwargs):
start_time = time.time()
ret_add = func(*args, **kwargs)
print '___执行完装饰器1___'
end_time = time.time()
result = end_time - start_time
return ret_add
return wrapper
def decorator2(func):
"""装饰器函数2, 带有参数"""
print '___进入装饰器2___'
def wrapper(*args, **kwargs):
start_time = time.time()
ret_add = func(*args, **kwargs)
print '___执行完装饰器2___'
end_time = time.time()
result = end_time - start_time
return ret_add
return wrapper
@decorator1
@decorator2
def func(x, y, z):
"""该函数有2个参数"""
time.sleep(2)
print '___执行函数__'
return x + y + z
print func(2, 3, z=20)
# 输出结果如下:
___进入装饰器2___
___进入装饰器1___
___执行函数__
___执行完装饰器2___
___执行完装饰器1___
25
它执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器
。
注意:相当于func = decorator1(decorator2(func))
使用装饰器类
:主要依靠类的__ call __
方法,当使用@形式将装饰器附加到函数上时,就会调用此方法:
class Dog(object):
def __init__(self, func):
self._func = func
def __call__(self, *args, **kwargs):
print '使用__call__方法前'
self._func()
print '使用__call__方法后'
@Dog
def func():
print '执行一个简单函数'
func()
# 输出结果如下:
使用__call__方法前
执行一个简单函数
使用__call__方法后