我该如何创建一个函数,等待一个表达式为真,然后返回它的一部分

时间:2019-06-28 20:10:14

标签: python

我想构建一个通用的“ waiter”函数,该函数将接受两段输入,一遍又一遍地对其求值,直到组合表达式的值为True,然后返回第一段输入的值。但是我什至不知道这种东西叫什么,所以我很难寻找它。

我有一个执行此操作的现有函数,但我想对其进行扩展,以便将单个lambda expression分为两部分,并返回第一部分的值。

这是我现有的代码:

def wait_until(expression, timeout=30, period=10, *args, **kwargs) -> None:
    """Wait until expression is true"""
    end_time = time.time() + timeout
    while time.time() < end_time:
        try:
            if expression(*args, **kwargs):
                log.debug("That's the one!")
                return
            else:
                log.debug("That's not the one")
        except Exception as e:
            log.debug(f"Exception caught and ignored while executing the predicate: {e}")
        time.sleep(period)
    log.error("Timed out")
    raise TimeoutError(f"Timed out waiting {timeout} seconds")

我可以使用如下功能:

>>> wait_until(lambda: random.randint(0, 9) % 2 == 0)

这是我想要的新的wait_until函数的行为。我想让它返回找到后被2整除的随机数,以使用相同的示例。

我对Python还是很陌生,因此鉴于该语言提供的功能,我不知道最佳方法。我正在使用3.7,顺便说一句。

>>> from random import randint
>>> wait_until(randint(0, 9), "% 2 == 0")
4
>>> wait_until(randint(0, 9), "== 10", Timeout=30)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TimeoutError: input expression was not "== 10" in less than 30 seconds

第二个参数不必一定是字符串。要点是将第一个参数返回的值与第二个参数比较以确定真相。并且第一个参数每次都会重新评估,因为它的值预计会发生变化。

1 个答案:

答案 0 :(得分:3)

您需要将expression参数分成两个参数:一个函数生成值,另一个函数测试值。然后,您调用生成器,将结果传递给测试器,如果成功,则返回值。

def wait_until(generator, tester, timeout = 30, period = 10, *args, **kwargs):
    end_time = time.time() + timeout
    while time.time() < end_time:
        try:
            val = generator(*args, **kwargs)
            if tester(val):
                log.debug("That's the one!")
                return val
            else:
                log.debug("That's not the one")
        except Exception as e:
            log.debug(f"Exception caught and ignored while executing the predicate: {e}")
        time.sleep(period)
    log.error("Timed out")
    raise TimeoutError(f"Timed out waiting {timeout} seconds")

print(wait_until(lambda: random.randint(0, 9), lambda x: x % 2 == 0))