装饰器的作用:在不更改原功能函数内部代码,并且不改变调用方法的情况下为原代码添加新的
功能。
装饰器原理阐述:将被装饰的函数当做一个参数传到装饰器中,并且让被装饰的函数名指向装饰
器内部的函数,在装饰器的内部函数中用接收到的参数再调用被00装饰的函数
1、普通装饰器
import time
def count_time(func):
def wrapper():
strat_time = time.time() #获取开始时的时间
func() #运行被装饰的函数
end_time = time.time() # 获取结束时的时间
t_time = end_time - strat_time #算出运行总时间
print('运行总时间%:',t_time) #打印运行总时间
return wrapper
@count_time
def work():
time.sleep(2)
print('原来函数的功能代码')
work()
2、装饰有参数和返回值函数
def count_time(func):
def wrapper(a,b):
strat_time = time.time()
# 调用功能函数,接收功能函数返回的结果
res = func(a,b)
end_time = time.time()
t_time = end_time - strat_time
print('运行总时间%:',t_time)
# 返回结果
return res
return wrapper b
3、通用装饰器
def count_time(func):
def wrapper(*args,**kwargs):
strat_time = time.time()
# 调用功能函数,接收功能函数返回的结果
res = func(args,kwargs)
end_time = time.time()
t_time = end_time - strat_time
print('运行总时间%:',t_time)
# 返回结果
return res
return wrapper
4、装饰器装饰类
def decorator(cls):
def wrapper(*args, **kwargs):
print("----装饰器扩展代码1------")
# 通过类实例化对象
res = cls()
print("----装饰器扩展代码2------")
#使用类装饰器的时候,记得要返回被装饰的类调用的结果
return res
return wrapper
@decorator # MyClass =decorator(MyClass)
class MyClass:
pass
5、装饰器传参数
最外层参数,接收的是装饰器的参数
第二层参数,接收是被装饰的函数
第三层参数,接收的是被装饰函数的参数
def musen(name, age):
def decoreter(func):
def wrapper(*args, **kwargs):
print("装饰器传递的参数name:", name)
print("装饰器传递的参数age:", age)
res=func(*args, **kwargs)
return res
return wrapper
return decoreter
@musen('11', 18) #
def work():
print("----work----")
6、类实现装饰器
前面我们是用闭包函数来实现的装饰器,那么接下来给大家扩展一下,使用类来当做一个装饰器
来用
如果要把类当做一个装饰器来用,有两步操作,
首先在 init 方法中,把被装饰的函数赋值给一个实例属性,
然后再了类里面实现一个 call 方法,在call方法中调用原来的函数。
class Test(object):
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
print('这个是类装饰器')
self.func(*args,**kwargs)
class Decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("装饰器扩展代码1111111111111")
res = self.func()
print("装饰器扩展代码2222222222")
return res
# 通过类作为装饰器
@Decorator # work = Decorator(work)
def work():
print("----work----------")
work()
#结果
装饰器扩展代码1111111111111
----work----------
装饰器扩展代码2222222222
7、装饰器的副作用
问题:函数/类 在被装饰器装饰了之后,会改变原函数名的指向,无法再通过原函数名去获取函数
原有的属性,
消除装饰器的副作用:functools.wraps
def decorator(func):
#@wraps(func) # 消除装饰器的副作用
def wrapper(*args, **kwargs):
"""装饰器内部wrapper的注释"""
res = func(*args, **kwargs)
return res
return wrapper
@decorator
def work(a, b):
"""
实现两个对象相加的方法
:param a: 数字1
:param b: 数字2
:return: 两个数相加的结果
"""
res = a + b
print('a+b的结果为:', res)
# 获取函数的文档字符串
print("函数的文档字符串注释:", work.__doc__)
# 获取函数的name属性
print('函数名:', work.__name__)
#结果
不加@wraps(func)
函数的文档字符串注释: 装饰器内部wrapper的注释
函数名: wrapper
加@wraps(func)
函数的文档字符串注释:
实现两个对象相加的方法
:param a: 数字1
:param b: 数字2
:return: 两个数相加的结果
函数名: work
8、通过装饰器修改属性
def mark(func):
func.name = '002'
return func
# 通过装饰器给原函数动态添加属性
@mark # work = mark(work)
def work():
print("----work----")
# work.name = '001'
# work()
print(work.name)#002