大家好~我是
米洛
!
我在从0到1打造一个开源平台, 也在编写一套完整的接口测试平台系列教程
,希望大家能够多多支持。
欢迎关注我的公众号米洛的测开日记
,获取最新文章教程!
本文讲述装饰器的一些运用场景,有兴趣的同学可以了解一下。
在此之前,我们先对一下上期作业
的答案吧,已经做对的同学可以往下拉
:
要求实现一个自定义的装饰器
这题的核心内容就是callable
,我们可以这么写:
def run(times):
if callable(times):
def wrapper(*args, **kwargs):
for i in range(5):
times(*args, **kwargs)
print(f"运行的第{i}次")
return wrapper
else:
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(times):
func(*args, **kwargs)
print(f"运行的第{i}次")
return wrapper
return decorator
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这里用到了一个核心方法: callable
callable的意思是,这个变量是不是可被调用
的,如果我们的run接受的是一个方法,那么它就会走if
里面的逻辑,反之则会再包一层decorator。
# 怎么区分呢
@run
def wqrf():
print("haha")
2
3
如果是这样,run后面没有接任何参数,甚至是括号
,单纯的就是@run,那么我们看看times变量会是什么呢?
大家可以先猜想一下
:
所以我们按照预先说的,如果run装饰器后面没有接参数,则调用5次
。(这里有一些改动,因为如果我不循环调用的话,那加这个装饰器毫无意义,所以我这边改成了: 不带参数则调用5次)
那再看看带参数的时候,times是什么内容:
而23自然是不会
触发callable条件的。
搞懂什么时候if callable
成立,那这个问题就好解决了。
如果它成立,那么它可以简写为:
def run(times):
def wrapper(*args, **kwargs):
for i in range(5):
times(*args, **kwargs)
print(f"运行的第{i}次")
return wrapper
2
3
4
5
6
7
如果不成立,则是另一个装饰器:
def run(times):
def decorator(func):
def wrapper(*args, **kwargs):
for i in range(times):
func(*args, **kwargs)
print(f"运行的第{i}次")
return wrapper
return decorator
2
3
4
5
6
7
8
9
10
所以,看似复杂
,实际上是根据接收的参数是否可调用
,从而选择变成什么样的装饰器
,这就完成了我们的作业了~
如果有疑惑的话,可以回忆一下上一篇装饰器
的写法。文末会附上完整代码。
# 回到主题
我们说了那么多,该讲下装饰器
的运用了。以下都是需求+例子,大家且看且珍惜~
计时器
当我们需要统计一些方法的执行时间,我们可以这么写。
def time_dec(func):
def wrapper(*arg):
t = time.perf_counter()
res = func(*arg)
print(func.__name__, time.perf_counter() - t)
return res
return wrapper
2
3
4
5
6
7
但你会发现装饰器的名字打印出来的时候,func.name 变成了wrapper,很正常,因为我们确实定义了个wrapper
。
只需要在装饰器def wrapper上面加上一个装饰器:
@functools.wraps(func)
异常捕获器(来自测试开发笋货的思路)
写try和except写厌烦了吧?你可以这么玩:
def exceptions(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
raise Exception(e)
return wrapper
2
3
4
5
6
7
8
- web开发中判断用户是否登录
def login_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
headers = request.headers
token = headers.get('token')
if token is None:
return jsonify(dict(code=401, msg="用户信息认证失败, 请检查"))
# 解析用户信息
user_info = UserToken.parse_token(token)
# 这里把user信息写入kwargs
kwargs["user_info"] = user_info
except Exception as e:
return jsonify(dict(code=401, msg=str(e)))
return func(*args, **kwargs)
return wrapper
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 数据驱动
@parameters(
(2, 4, 6),
(5, 6, 11),
)
def test_add(a, b, expected):
assert a + b == expected
2
3
4
5
6
类似于ddt库提供的数据驱动方法,用于测试用例。
日志记录
用例重跑
UI用例执行异常自动截图
这个与笋货类似,捕获异常以后进行
额外
的处理。给变量加锁
import functools
def synchronized(lock):
""" Synchronization decorator """
def wrap(f):
@functools.wraps(f)
def newFunction(*args, **kw):
with lock:
return f(*args, **kw)
return newFunction
return wrap
2
3
4
5
6
7
8
9
10
11
今天的内容就简单介绍到这里了,收尾明显有点潦草
,因为有个同事催我下班了,哈哈~
下次再会···