2014-04-14 31 views
1

我經常使用的模式是這樣發現自己:轉換while循環的東西可重用

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 

或者,也許有什麼東西在會做的伎倆標準庫?

回答

1

您可以使用一臺發電機,睡然後返回重複的結果。 的好處是你的來電者仍然是一個真正的循環,與 所有的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 ... 
+0

這看起來像一個最靈活的方法。額外的+++名稱;) – georg

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)告訴裝飾它還沒有完成。

+0

我喜歡裝飾者的想法,但由於範圍問題,並不總是可能將「可重複」邏輯封裝在函數中。 – georg

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)) 

或類似的東西

+1

其中一個缺點是,這種方法實際上並沒有給你'我' - 你可以'返回'而不是'休息'。 – jonrsharpe