运行一个函数,直到它第一次返回True,然后不要再运行它



我正在开发一个接收连续数字输入流的模块。目标是检测输入数组超过某个预设阈值的第一次时间。换句话说,我需要运行一个比较函数,直到达到阈值;则该函数需要是"0";关闭;

我的想法是用decorator来解决这个问题,因为我知道它们只能有效地用于运行一个函数一次,再也不能运行了,这与我试图实现的有点相似。

在以下情况下,数字输入的连续流为:12, 19, 82, 92, 26, ...。在这种情况下,预期输出为:

Rand. val:  12
above_threshold returns False
Rand. val:  19
above_threshold returns False
Rand. val:  82
above_threshold returns True 
Threshold has been reached! 
Comparison function above_threshold shouldn't be called any more.
Rand. val: 92
Rand. val: 26
...

然而目前CCD_ 2在每个循环中都被调用;"关断";使用decorator的函数。

import time 
import random 
random.seed(12771)
threshold = 75
def run_until_first_true_reached(f):
"""
Decorator that runs the function f until it first returns True. 
After returning True once, it will stop running the wrapped function again.
"""
def wrapper(*args, **kwargs):
# If f is False
if not f(*args, **kwargs):
return f(*args, **kwargs)
# If f is True
else: 
print("Threshold has been reached!")
print("Comparison function above_threshold shouldn't be called any more.")
# tried an empty "return" in this line but didn't solve the issue
return wrapper 
@run_until_first_true_reached
def above_threshold(value, threshold): 
if value > threshold:
print("above_threshold returns True")
return True 
else:   
print("above_threshold returns False")
return False
# Modelling the continuous stream of inputs 
for _ in range(100): 
rand_val = random.randint(1,100)
print("Rand. val: ", rand_val)
above_threshold(rand_val, threshold)
time.sleep(1)

我不知道有什么方法可以在达到条件后不调用decorator/包装器,但一旦达到条件,就可以将其转换为no-op,这很简单,根据您的第一个注释,这似乎是您希望代码执行的操作。

import time 
import random 
random.seed(12771)
threshold = 75
def run_until_first_true_reached(f):
"""
Decorator that runs the function f until it first returns True. 
After returning True once, it will stop running the wrapped function again.
"""
def wrapper(*args, **kwargs):
if not wrapper.reached:
v = f(*args, **kwargs)
# If f is False
if not v:
return v
# If f is True
else: 
print("Threshold has been reached!")
print("Comparison function above_threshold shouldn't be called any more.")
wrapper.reached = True
return None   #  ? or wahtever we want to return once the threshold is reached
wrapper.reached = False
return wrapper 
@run_until_first_true_reached
def above_threshold(value, threshold): 
if value > threshold:
print("above_threshold returns True")
return True 
else:   
print("above_threshold returns False")
return False
# Modelling the continuous stream of inputs 
for _ in range(100): 
rand_val = random.randint(1,100)
print("Rand. val: ", rand_val)
above_threshold(rand_val, threshold)
time.sleep(1)

结果:

Rand. val:  12
above_threshold returns False
Rand. val:  19
above_threshold returns False
Rand. val:  82
above_threshold returns True
Threshold has been reached!
Comparison function above_threshold shouldn't be called any more.
Rand. val:  92
Rand. val:  26
Rand. val:  18
Rand. val:  55
...

这里有趣的一点是,你需要一个地方来存储状态。。。已经达到阈值的事实。我在decorator中这样做的方法是将状态附加到包装器函数。

我稍微更改了您的逻辑,这样每次调用包装器时就不会两次调用包装函数。这产生了重复的输出行,导致无法匹配您请求的输出。

简单地使用这个想法,你想要的是:"接通和断开";包装函数的调用。为此,我们可以使用父decorator函数的一个变量作为状态标志:

import time 
import random 
random.seed(12771)
threshold = 75
def run_until_first_true_reached(f):
"""
Decorator that runs the function f until it first returns True. 
After returning True once, it will stop running the wrapped function again.
"""
switch_on = True
def wrapper(*args, **kwargs):
nonlocal switch_on
if switch_on:
threshold_reached = f(*args, **kwargs)
if threshold_reached:
print("Threshold has been reached!")
print("Comparison function above_threshold shouldn't be called any more.")
switch_on = False
return wrapper 
@run_until_first_true_reached
def above_threshold(value, threshold): 
if value > threshold:
print("above_threshold returns True")
return True 
else:   
print("above_threshold returns False")
return False

输出:

Rand. val:  12
above_threshold returns False
Rand. val:  19
above_threshold returns False
Rand. val:  82
above_threshold returns True
Threshold has been reached!
Comparison function above_threshold shouldn't be called any more.
Rand. val:  92
Rand. val:  26
Rand. val:  18
Rand. val:  55

最新更新