示例1:普通装饰器
def name(n):
def func(x):
res = n(x+x)
return res
return func
@name
def run(x): # run = name(run)
print(x)
if __name__ == '__main__':
run(1)
# 2
def name(n):
def func(*x):
res = n(x+x)
return res
return func
@name
def run(x): # run = name(run)
print(x)
if __name__ == '__main__':
run(1)
# (1, 1)
上述二者的比较,注意传参参数。一个是普通的传值,一个是两个元组相加。
示例2:普通装饰器传值
def name(n):
def func(x, y):
res = n(x,y)
return res
return func
@name
def run(x, y): # run = name(run)
print(x, y)
if __name__ == '__main__':
run(1, 2)
# 1 2
试想,如何才能实现1+2,run函数中还是name函数中
def name(n):
def func(x, y):
res = n(x,y)
return res
return func
@name
def run(x, y): # run = name(run)
print(x + y)
if __name__ == '__main__':
run(1, 2)
在run函数中实现,name函数作用近似于调用的操作,也可以在name函数中实现
def name(n):
def func(x, y):
res = n(x,y)
print(x + y)
return res
return func
@name
def run(x, y): # run = name(run)
# print(x + y)
pass
if __name__ == '__main__':
run(1, 2)
示例3-进阶:日志
import logging
def name(n):
def func(x, y):
res = n(x,y)
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(message)s', level=logging.DEBUG)
logging.info("执行了{},{},结果是{}".format(x,y,res))
return res
return func
@name
def run(x, y): # run = name(run)
return x+y
if __name__ == '__main__':
run(1, 2)
# 2023-03-01 12:24:10,474 root 20 ceshi_test.py 10 执行了1,2,结果是3
这里的结果貌似没有指明函数,影响不大,可以看看logging模块,也可以自己加。
import logging
def name(n):
def func(x, y):
res = n(x,y)
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)
logging.info("执行了{},{},{},结果是{}".format(n.__name__,x,y,res))
return res
return func
@name
def run(x, y): # run = name(run)
return x+y
if __name__ == '__main__':
run(1, 2)
# 2023-03-01 12:35:15,283 root 20 ceshi_test.py 9 func 执行了run,1,2,结果是3
可以看到,获取的运行函数其实不太一样。要想准确的获取,建议手写
示例4-进阶:时间计时器
import time
def timer(clock):
def func(*args,**kwargs):
start = time.time()
res = clock(*args,**kwargs)
print("耗时 {} S".format(time.time() - start))
return res
return func
@timer
def run(x, y):
time.sleep(1)
print(x + y)
if __name__ == '__main__':
run(1, 2)
# 3
# 耗时 1.0103626251220703 S
上述是在不做任何操作的情况下,单纯用来计算程序运行时间。
示例5-再进阶-带参
def outwapper(out):
def country(cont):
def inwapper(*args,**kwargs):
if out == '中国':
print("你好啊,兄弟")
else:
print("你是哪个国家的")
cont(*args,**kwargs)
return inwapper
return country
@outwapper("中国")
def people():
pass
if __name__ == '__main__':
people()
是不是看起来麻烦了很多,仔细一看其实也久那么回事。传个参数,该返回的值还是得返回。
def outwapper(out):
def country(cont):
def inwapper(*args,**kwargs):
if out == '中国':
print("你好啊,兄弟")
else:
print("你是哪个国家的")
cont(*args,**kwargs)
return inwapper
return country
@outwapper("中国")
@outwapper("俄罗斯")
def people():
pass
if __name__ == '__main__':
people()
# 你好啊,兄弟
# 你是哪个国家的
可以多个装饰器作用同一个函数上,也能重复使用。
示例6-高阶-类装饰器
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(args,kwargs)
@Time
def name():
pass
if __name__ == '__main__':
name()
套用格式即可,__init__中的参数是必须的,因为需要传递函数。
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print(args,kwargs)
@Time
def name(x,y):
pass
if __name__ == '__main__':
name('萌萌',age=18)
# ('萌萌',) {'age': 18}
很明显了吧,__call__中用来接收值并处理的。
传参
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, evt):
def wapper(*args, **kwargs):
print(self.func, args, kwargs)
return wapper
@Time("中国")
def name(x, y):
pass
if __name__ == '__main__':
name('萌萌', age=18)
# 中国 ('萌萌',) {'age': 18}
evt是啥?
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, evt):
def wapper(*args, **kwargs):
print(evt.__name__, args, kwargs)
return wapper
@Time("中国")
def name(x, y):
print(x,y)
if __name__ == '__main__':
name('萌萌', age=18)
# name ('萌萌',) {'age': 18}
就是name函数的函数地址,如何使用evt参数呢?
class Time(object):
def __init__(self, func):
self.func = func
def __call__(self, evt):
def wapper(*args, **kwargs):
evt(args,kwargs)
# print(evt.__name__, args, kwargs)
return wapper
@Time("中国")
def name(x, y):
print(x,y)
if __name__ == '__main__':
name('萌萌', age=18)
就是这么简单。
示例7-高阶-装饰类的装饰器
def func(cls):
def inwapper(*args,**kwargs):
print(cls.__name__)
print(args)
return inwapper
@func
class User:
def __init__(self,name):
self.name = name
if __name__ == '__main__':
User("萌mengan")
# User
# ('萌mengan',)
类中函数使用装饰器
def func(cls):
def inwapper(x, *args, **kwargs):
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)
logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
return inwapper
# @func
class User:
@func
def name(self, name, name1, age):
# return name, name1, age
pass
if __name__ == '__main__':
u = User()
u.name("萌萌","ANAN",age=18)
2023-03-01 18:36:36,310 root 20 ceshi_test.py 74 inwapper 执行了name,结果是<__main__.User object at 0x0000020A11DABE50>,('萌萌', 'ANAN'),{'age': 18}
为什么要有个x,因为self会被当作参数传递,直接把内存地址一起传走了,要么下标取值要么再来个参数接收这个self。要么类中不使用self
❝既然使用了self,那么装饰器中能用来调用属性吗,答案是当然可以。
❞
def func(cls):
def inwapper(x, *args, **kwargs):
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)
x.info = 1
logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
return inwapper
class User:
info = None
@func
def name(self, name, name1, age):
# return name, name1, age
pass
if __name__ == '__main__':
u = User()
u.name("萌萌","ANAN",age=18)
print(u.info)
# 1
# 2023-03-02 09:15:36,640 root 20 ceshi_test.py 75 inwapper 执行了name,结果是<__main__.User object at 0x0000021B20A2F5B0>,('萌萌', 'ANAN'),{'age': 18}
❝显而易见,赋值成功。再来看看对其他函数赋值。
❞
def func(cls):
def inwapper(x, *args, **kwargs):
logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s '
'%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)
x.Info("QA",18)
logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))
return inwapper
class User:
info = None
@func
def name(self, name, name1, age):
# return name, name1, age
pass
def Info(self,name,age):
print("我是{},今年{}".format(name,age))
if __name__ == '__main__':
u = User()
u.name("萌萌","ANAN",age=18)
# 2023-03-02 09:19:26,910 root 20 ceshi_test.py 75 inwapper 执行了name,结果是<__main__.User object at 0x00000232FF01F5B0>,('萌萌', 'ANAN'),{'age': 18}
# 我是QA,今年18
示例8-伪装
from functools import wraps
def timer(value):
def func(fun):
# @wraps(fun)
def inner(*args,**kwargs):
res = fun()
print(value)
print(inner.__name__)
return res
return inner
return func
@timer("QA")
def run():
pass
if __name__ == '__main__':
run()
❝伪装装饰器,让装饰器函数名称指向运行函数名。
❞
此外还有一些用法,此处就不再阐述,学习完上述的示例后,你是否能自己写出一个像样的装饰器呢?
最后: 下方这份完整的软件测试视频学习教程已经整理上传完成,朋友们如果需要可以自行免费领取【保证100%免费】
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!