一、不带参数的装饰器
"""
不带参数的装饰器
装饰器 返回函数的函数
可以写多个
"""
def log(func):
"""记录函数执行的日志"""
def wrapper():
print("装饰器1 start...")
func()
print("装饰器1 end.")
return wrapper
def log_in(func):
"""记录函数执行的日志"""
def wrapper():
print("装饰器2 start...")
func()
print("装饰器2 end.")
return wrapper
@log
@log_in
def hello():
"""简单功能模拟"""
print("hello world")
if __name__ == '__main__':
hello()
运行的结果
二、带参数的装饰器
1.添加装饰器的函数没有参数
在原来装饰器的外边嵌套一层装饰器,外部的嵌套的参数可以使用 查看hello()的打印结果
2.函数有参数
有些函数带参数本身就带了参数定义内部装饰器的时候需要传进去
如果函数返回值,内部装饰器先临时保存结果,最后在返回
from functools import wraps
def log(name=None):
"""记录函数执行的日志"""
def decorator(func):
@wraps(func) # 内部提供的装饰器 对以前写好的函数使用装饰器之后的信息不会发生改变
def wrapper(*args, **kwargs): # 传参使用魔法方法传入
"""装饰器内部的函数"""
# 内部装饰器对原有的函数名称文档信息发生了改变
print("{0} start...".format(name))
print("---wrapper:{0}".format(func.__doc__)) # 在这里查看一下是否已经改变了文档信息
print("---wrapper:{0}".format(func.__name__)) # 在这里查看一下是否已经改变了函数名称
temp = func(*args, **kwargs) # 用临时变量保存结果返回 add函数有返回
print("{0} end.".format(name))
return temp
# wrapper.__doc__ = func.__doc__
# wrapper.__name__ = func.__name__
return wrapper
return decorator
@log('you') # 这里需要传参数 不传默认None
def hello():
"""简单功能模拟"""
print("hello world")
if __name__ == '__main__':
print('doc:{0}'.format(hello.__doc__))
print('doc:{0}'.format(hello.__name__))
hello()
这里@wraps的使用是内部提供的装饰器
需要导入 from functools import wraps
,当装饰器内部的wrapper()
函数前没有添加@wraps
时,在主方法中打印hello()
函数的文档信息和名称获取到的是 如下结果
2.1注释掉@wraps执行的结果
得到的hello的文档信息已经发生了改变
2.2添加@wraps的执行结果
总结一下
1.添加内部提供的装饰器@wraps,可以对以前写好的函数再使用装饰器之后,原本函数的信息不会发生改变,所以每次写装饰器的时候我都添加一下@wraps
2.如果函数带有参数,在装饰器内也要传入参数,使用魔法方法*args,**kwargs
在装饰器内部传参
3.函数内不如add()函数有返回值,在装饰器内部用临时变量对结果保存,最后再返回一下