功能:
为已存在的函数或对象添加额外的功能
原则:
- 不改变源代码为其添加功能
- 不改变函数的调用方式
方法:
装饰器 = 高阶函数 + 嵌套函数
(高阶函数:一个函数可以作为参数传递给另外一个函数,或者,一个函数的返回值是一个函数,即函数的入口地址)
- 函数名作为参数传递给装饰器(@decorator_name)
- 装饰函数返回函数名(函数地址)
注意:
- 默认情况下,装饰器会修改名字和文档说明,但是可以使用functools中 的@wraps()解决。@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。
- 装饰器作用于函数上,但是如果装饰器装饰在一个类上面,相当于为类中的所有方法都加上了装饰器
def decorator(func):
"""
decorator __doc__
"""
# @wraps(func)
def wrapper(*args, **kwargs):
"""wrapper __doc__"""
func()
return wrapper
@decorator
def test():
"""test __doc__"""
time.sleep(0.5)
test(1, 2)
print("function name:", test.__name__)
print("function doc :", test.__doc__)
# output:
# function name: wrapper
# function doc : wrapper __doc__
# 加了@wraps(func)后的output:
# function name: test
# function doc : test __doc__
例子:
1. 函数作为装饰器
此例子实现了一个计算调用函数所占用的时间
import time
from functools import wraps
def decorator(func):
"""
function:decorator
"""
@wraps(func)
def wrapper(*args, **kwargs):
"""function:wrapper"""
start = time.time()
ret = func(*args, **kwargs)
end = time.time()
print("function {0} run time: {1}".format(func.__name__, end - start))
# print("function {fun} run time: {time}".format(fun=func.__name__, time=end - start))
return ret
return wrapper
@decorator
def test(a, b, name="Lizo"):
"""function:test"""
time.sleep(0.5)
print(a, b, name)
2.类作为装饰器
为什么可以使用类作为装饰器?因为在Python中,一切皆对象,其实函数也是一个对象,如果一个类实现了 __call__(self)方法后,就可以像调用函数一样,直接加一个括号就可以调用。
class Runtime:
def __init__(self):
pass
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
end = time.time()
print("function: {func} run time: {time}".format(func=func.__name__, time=end - start))
return ret
return wrapper
#使用装饰器方法1
runtime = Runtime()
@runtime
def test_class_decorator1():
print("in the test_class_decorator")
time.sleep(0.2)
#使用装饰器方法2
@Runtime()
def test_class_decorator2():
print("in the test_class_decorator")
time.sleep(0.2)
class Runtime:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
# @wraps(self.func)
start = time.time()
ret = self.func(*args, **kwargs)
end = time.time()
print("function: {func} run time: {time}".format(func=self.func.__name__, time=end - start))
return ret
@Runtime
def test_class_decorator1():
print("in the test_class_decorator")
time.sleep(0.2)
3.带参数的装饰器
如果需要装饰器接收参数,则需要添加一层函数
import time
from functools import wraps
def decorator(a):
def inner(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
end = time.time()
print("function {0} run time: {1}".format(func.__name__, end - start))
return ret
return wrapper
return inner
@decorator(a=1)
def test(a, b, name="Lizo"):
pass