Python自定义装饰器以及while 循环

装饰器可以简化代码,使用起来也很方便,下面给出一个示例:

一、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循环,都可以复用该装饰器,简化了重复写代码的步骤,且所有循环均保持一致的逻辑