01、普通装饰器
详解 python 各种装饰器的实现,我们先来看一个普通的装饰器函数。
def decorator(fun):
def func_w():
print('---装饰器扩展的新功能')
fun()
return func_w
@decorator :
def func_demo(a,b):
res = a/b
print('a除B的结果为:',res)
# @decorator这是样的写法是python中的一个语法糖,
#它的一个等同所有就是原来的这句 @decorator=====》func_demo= decorator(func_demo)
**装饰器原理阐述:**将被装饰的函数当做一个参数传到装饰器中,并且让被装饰的函数名指向装饰器内部的函数,在装饰器的内部函数中用接收到的参数再调用被装饰的函数。
**案列、**使用装饰器来统计函数运行的时间
import time
def decorator(func):
def fun():
strat_time = time.time() #获取开始时的时间
func() #运行被装饰的函数
end_time = time.time() # 获取结束时的时间
t_time = end_time - strat_time #算出运行总时间
print('运行总时间%s'%t_time) #打印运行总时间
return fun
@decorator
def work():
time.sleep(2)
print('原来函数的功能代码')
work()
如果你想学习自动化测试,我这边给你推荐一套视频,这个视频可以说是B站播放全网第一的自动化测试教程,同时在线人数到达1000人,并且还有笔记可以领取及各路大神技术交流:798478386
【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)_哔哩哔哩_bilibili【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)共计200条视频,包括:1、接口自动化之为什么要做接口自动化、2、接口自动化之request全局观、3、接口自动化之接口实战等,UP主更多精彩视频,请关注UP账号。https://www.bilibili.com/video/BV17p4y1B77x/?spm_id_from=333.337
02、装饰带参数的函数
● 被装饰器的函数带参数怎么处理?
在内部的闭包函数中接收一个参数,然后在调用原功能函数时再把接收到的参数传入即可。
def decorator(func):
def fun(a,b):
print('-----装饰器实现的功能-------'))
func(a,b)
return fun
@decorator
def func(a,b):
print("----执行函数--func-----")
print(a+b)
03、通用装饰器
● 被装饰的函数,一部分带参数,一部分不带参数怎么处理?
○ 如果同一个装饰器既要装饰有参数的函数,又要装饰无参数的函数,那么我们在传参的时候就设置成不定长参数,这样不管被装饰的函数有没有参数都能用。
def decorator(func):
def fun(*args,**kwargs):
print('-----执行装饰器实现的功能-------')
func(*args,**kwargs)
return fun
@decorator
def func(a,b,f):
print("----执行函数--func-----")
print(a+b+f)
func(10,20,30)
04、装饰器装饰类
装饰器装饰类本质上和装饰函数没有区别,同样是把被装饰的类和函数当成参数传入装饰器中,把返回的结果传递给原来定义的类去接收。
就是说装饰完之后,原来定义的类名,指向的就是装饰器内部的嵌套函数了。
def decorator(func):
def fun(*args,**kwargs):
print('-----执行装饰器实现的功能-------')
return func(*args,**kwargs)
return fun
@decorator # @decorator 等同于 Hero = decorator(Hero)
class Hero(object):
def __init__(self,name,age):
self.name=name
self.age=age
print('正在初始化')
def move(self):
print('%s在快速移动'%self.name)
laoli = Hero('老李',19)
使用类装饰器的时候,记得要返回被装饰的类调用的结果。
05、装饰器传参数
前面介绍的几种装饰器在使用的时候不需要传递参数,那么如果在装饰器的时候需要传参数该怎么去实现呢?
# 定义可以传参的装饰器
def musen(name, age):
def decoreter(func):
def wrapper(*args, **kwargs):
print("装饰器传递的参数name:", name)
print("装饰器传递的参数age:", age)
func(*args, **kwargs)
return wrapper
return decoreter
# 使用装饰器并传参
@musen('木森',18)
def work():
print('原功能函数的代码')
# 代码解析:上面装饰的哪一行代码,的效果等同于work = musen('木森',18)(work)
# 意思就是先调用musen('木森',18) 使用调用的结果去装饰work,然后再把结果赋值给work
总结:
● 最外层参数,接收的是装饰器的参数
● 第二层参数,接收是被装饰的函数
● 第三层参数,接收的是被装饰函数的参数
06、类实现装饰器
前面我们是用闭包函数来实现的装饰器,那么接下来给大家扩展一下,使用类来当做一个装饰器来用
● 如果要把类当做一个装饰器来用,有两步操作,
○ 首先在 __init__ 方法中,把被装饰的函数赋值给一个实例属性,
○ 然后再了类里面实现一个 __call__ 方法,在 call 方法中调用原来的函数。
class Test(object):
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
print('这个是类装饰器')
self.func(*args,**kwargs)
#说明:
#1. 当用Test来装作装饰器对func函数进行装饰的时候,首先会创建Test的实例对象,并且会把func这个函数名当做参数传递到__init__方法中,即在__init__方法中的func变量指向了func函数体
#2. func函数相当于指向了用Test创建出来的实例对象
#3. 当在使用func()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
#4. 为了能够在__call__方法中调用原来func指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用,所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到func之前的函数体