装饰器概念
一个简单的语法糖,或者说是一个特殊的高阶函数.
通过保证目标函数来修改其行为, 绝大多数装饰器 都是通过闭包的原理 来实现的.
@cache
def function():....
等同于
def function():...
function = cache(function)
无参数的装饰器
"""
没有参数的装饰器
功能: 打印包装函数的执行时间
"""
import time
def timer(func):
def decorated(*args, **kwargs):
st = time.perf_counter()
ret = func(*args, **kwargs)
print("cost time", time.perf_counter() - st)
return ret
return decorated
@timer
def sleep_func():
time.sleep(1)
if __name__ == '__main__':
sleep_func()
有参数的装饰器
给刚才的timer装饰器,加上
print_agrs
参数,是否打印参数
"""
没有参数的装饰器
功能: 打印包装函数的执行时间
"""
import time
def timer(print_args=False):
def decorated(func):
def wrapper(*args, **kwargs):
st = time.perf_counter()
ret = func(*args, **kwargs)
if print_args:
print("调用参数", args, kwargs)
print("cost time", time.perf_counter() - st)
return ret
return wrapper
# 带参数,外层其实是个保证,返回装饰器函数
return decorated
@timer(print_args=True)
def sleep_func(port, ip="127.0.0.1"):
"""文档注释"""
time.sleep(1)
if __name__ == '__main__':
sleep_func(8888)
print(sleep_func.__name__)
help(sleep_func)
# 这是因为装饰器再包装目标函数的时候,丢失了函数的元信息,是一种副作用
# 函数名字和help信息都丢了 functools.wraps 可以
"""
相当于
_decorated = timer(print_args=True)
sleep_func = _decorated(sleep_func)
或
sleep_func = timer(print_args=True)(sleep_func)
有参数的装饰器明显难写了不少, 可以看到, 我们比无参数的装饰器多调用了一次,实现代码也多了一层函数嵌套.
后面我们会用类来实现有参数的装饰器,可以明显较少代码嵌套的层数
"""
使用functools.wraps()
修饰包装函数
import time
from functools import wraps
def timer(print_args=False):
def decorated(func):
# 新增到这,加到被装饰的函数
@wraps(func)
def wrapper(*args, **kwargs):
st = time.perf_counter()
ret = func(*args, **kwargs)
if print_args:
print("调用参数", args, kwargs)
print("cost time", time.perf_counter() - st)
return ret
return wrapper
return decorated
@timer(print_args=True)
def sleep_func(port, ip="127.0.0.1"):
"""文档注释"""
time.sleep(1)
if __name__ == '__main__':
sleep_func(8888)
print(sleep_func.__name__)
help(sleep_func)
类装饰器
类装饰器,主要运用
__call__
可调用对象这个特性
import time
from functools import wraps
class Timer:
def __init__(self, print_args):
self.print_args = print_args
def __call__(self, func):
@wraps(func)
def decorated(*args, **kwargs):
s = time.time()
ret = func(*args, **kwargs)
if self.print_args:
print(ret)
print(time.time() - s)
return ret
return decorated
@Timer(False)
def hello():
time.sleep(1)
return "www"
if __name__ == '__main__':
hello()
另一种方式实现类装饰器
import time
from functools import wraps, update_wrapper
class Timer:
def __init__(self, func):
update_wrapper(self, func)
self.func = func
def __call__(self, *args, **kwargs):
s = time.time()
ret = self.func(*args, **kwargs)
print(time.time() - s)
return ret
@Timer
def hello():
time.sleep(1)
return "www"
if __name__ == '__main__':
hello()
再加一种
import time
from functools import wraps, update_wrapper, partial
class Timer:
def __init__(self, func, *, args1=None):
update_wrapper(self, func)
self.func = func
self.args1 = args1
def __call__(self, *args, **kwargs):
s = time.time()
ret = self.func(*args, **kwargs)
print(time.time() - s)
print(self.args1)
return ret
def delayed_start(**kwargs):
return partial(Timer, **kwargs)
@delayed_start(args1="ccc")
def hello():
time.sleep(1)
return "www"
if __name__ == '__main__':
hello()