装饰器
基本概念
- python函数的装饰器其实就是一个函数,它接受一个函数作为参数并返回一个新的函数
- python函数的装饰器仅会在函数被初始化的时候调用一次
functools
库的wraps
函数用来保留原始函数的重要元信息,使用装饰器时最好都添加该注解- 并不是所有的装饰器都使用了
wraps
函数,特别的,classmethod
和staticmethod
就没有遵守 - 给类或静态方法提供装饰器时,需要确保装饰器在
@classmethod
或 @staticmethod
之前,即确保它们出现在装饰器的第一个位置
示例
示例1: 普通装饰器(计算函数执行时间)
# coding: utf-8
import typing
import functools
import time
def compute_time(func: typing.Callable):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print('time spend', end_time - start_time)
return result
return wrapper
@compute_time
def test1():
for i in range(10):
time.sleep(0.1)
def test2():
for i in range(10):
time.sleep(0.1)
if __name__ == '__main__':
# 以下两种运行方式,结果相同
test1()
compute_time(test2)()
执行结果
time spend 1.0140540599822998
time spend 1.0238919258117676
示例2: 带参数的装饰器(失败重试,限制最大重试次数)
# coding: utf-8
import functools
def retries(max_reties=2):
def produce(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for i in range(max_reties):
try:
print('produce num', i)
return func(*args, **kwargs)
except Exception as e:
if i < (max_reties - 1):
continue
else:
raise e
return wrapper
return produce
@retries(3)
def ready():
print('start to produce')
raise Exception('error')
if __name__ == '__main__':
try:
ready()
except Exception as e:
print(e)
执行结果
produce num 0
start to produce
produce num 1
start to produce
produce num 2
start to produce
error
示例3:类的静态方法装饰器
# coding: utf-8
import functools
import time
import typing
def compute_time(func: typing.Callable):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print('time spend', end_time - start_time)
return result
return wrapper
class Calculator(object):
# 注意,如果以下两个装饰器的顺序错误,执行报错
@staticmethod
@compute_time
def add(a: int, b: int) -> int:
return a + b
if __name__ == '__main__':
calculate_result = Calculator.add(1, 3)
print(calculate_result)
执行结果
time spend 9.5367431640625e-07
4
python装饰器可以用来做很多事情,例如为被包装函数增加参数,扩充类的功能等等