装饰器可以简化代码,使用起来也很方便,下面给出一个示例:
一、while循环一般写法
一个while循环,通常情况下的写法是while True,但是容易引发无法跳出循环的bug,因此必须设置一个超时时间,更好的写法如下:
def func():
print(f"执行func函数")
time.sleep(1)
return True
import time
tout = time.time() + 60 # 设置超时时间60s
while time.time() < tout:
if func():
break
else:
time.sleep(1)
else:
raise TimeoutError
print(f"跳出循环")
上述例子中,如果func一直返回False,那么60s以后就会引发Timeout超时错误;直到返回了True,输出:“跳出循环”
二、装饰器实现
利用装饰器简化上述代码,实现在一段时间内循环执行代码,超时引发timeout。关于装饰器的定义以及如何定义简单的装饰器,自行在百度搜索教程。
(1)定义装饰器
这里给出的示例允许传入参数,以及读取被装饰函数的某些参数(result = kwargs.get(end_condition)-读取kwargs里的名为end_condition的参数)
def my_timer(total_time: float, interval: float, end_condition, customize: bool = True):
"""设计一个计时器装饰器,用于在一定时间内循环执行某个函数
:param total_time: 超时时间
:param interval: 等待间隔
:param end_condition: 结束循环的条件, customize = True
:param customize: result是否自定义,False-则获取func的某个参数的值,end_condition需要等于参数的名称
:return:
"""
def decorator(func):
@wraps(func) # 维持原函数的属性与函数名
def wrapper(*args, **kwargs):
# args位置参数, kwargs关键字参数
if customize:
result = end_condition
else:
# **获取func的关键字参数(end_condition为参数名称),不允许使用位置参数进行传参**
result = kwargs.get(end_condition)
tout = time.time() + total_time
while time.time() < tout:
if (ret := func(*args, **kwargs)) == result:
return ret
else:
condition = isinstance(result, str) and isinstance(ret, str)
if condition and result in ret:
# 若结果是字符串
return ret
elif isinstance(end_condition, type) and isinstance(ret, end_condition):
# end_condition可以是一个类型int\str\float...
return ret
time.sleep(interval)
else:
raise TimeoutError
return wrapper
return decorator
(2)调用装饰器
使用(1)中定义的装饰器简化上述的while循环示例
@my_timer(total_time=60, interval=1, end_condition=True)
def func():
print(f"执行不带参数的func函数")
return True
@my_timer(total_time=60, interval=1, end_condition="param", customize=False)
def func(param: str):
# 跳出循环的条件设置为参数“param”,当func的返回值为param时,跳出循环
print(f"执行带参数的func函数")
return param
这样做的好处是,之后无论在哪里用到了while循环,都可以复用该装饰器,简化了重复写代码的步骤,且所有循环均保持一致的逻辑