我经常发现自己使用这样的模式:
num_repeats = 123
interval = 12
for _ in xrange(num_repeats):
result = ...
if result meets condition:
break
time.sleep(interval)
else:
raise Failed despite multiple attempts
基本上,它会重复代码,直到返回正确的结果或计数器到期为止。
虽然这有效但对我来说看起来太冗长了。有可能"参数化"这个循环到可重用的函数或上下文管理器,例如
with repeat(num_repeats, interval):
code
或许标准库中有什么东西可以解决这个问题?
答案 0 :(得分:1)
一种方法是装饰你想要重复的功能:
def repeats_until(num_repeats, interval, condition):
def deco(f):
def func(*args, **kwargs):
for _ in xrange(num_repeats):
result = f(*args, **kwargs)
if condition(result):
return result
time.sleep(interval)
return func
return deco
然后使用它:
@repeats_until(3, 5, lambda s: s == "hello")
def take_input():
return raw_input("Say hello: ")
示例(虽然我无法显示等待!)
>>> take_input()
Say hello: foo
Say hello: bar
Say hello: baz
>>> take_input()
Say hello: hello
'hello'
或者,要使用被调用函数保持条件,例如:
def repeats(num_repeats, interval):
def deco(f):
def func(*args, **kwargs):
for _ in xrange(num_repeats):
result = f(*args, **kwargs)
if result is not None: # or e.g. False if None is valid return
return result
time.sleep(interval)
return func
return deco
@repeats(3, 5)
def take_input(condition):
s = raw_input("Say hello: ")
if condition(s):
return s
ui = take_input(lambda s: s == "hello")
这依赖于修饰函数返回一个值(在这种情况下是隐式None
),它告诉装饰者它还没有完成。
答案 1 :(得分:1)
你肯定无法使用with
语句,因为python只在代码运行之前和之后提供钩子,但不提供用于调用它的钩子,即。您无法在with
语句中隐藏循环。
一个很好的方法是使用lambda函数:
def repeat(repeats, interval, func):
for i in xrange(repeats):
if func(i):
break
time.sleep(interval)
然后你可以很容易地使用它:
repeat(123, 12, lambda i: condition(i))
或类似的东西
答案 2 :(得分:1)
您可以使用在返回重复结果之前休眠的生成器。
优点是你的调用者仍然是一个真正的for循环,有
所有break
,continue
,else
语义仍然有效。
def trickle_range(num_repeats, interval):
yield 0
for k in xrange(1, num_repeats):
time.sleep(interval)
yield k
for k in trickle_range(num_repeats, interval):
... do stuff, iterate or break as you like ...