2009-04-13 92 views
495

我需要模擬Python程序中的do-while循環。不幸的是,下面簡單的代碼不起作用:模擬Python中的do-while循環?

l = [ 1, 2, 3 ] 
i = l.__iter__() 
s = None 
while True : 
    if s : 
    print s 
    try : 
    s = i.next() 
    except StopIteration : 
    break 
print "done" 

而不是「1,2,3,做了」,它輸出以下:

[stdout:]1 
[stdout:]2 
[stdout:]3 
None['Traceback (most recent call last): 
', ' File "test_python.py", line 8, in <module> 
    s = i.next() 
', 'StopIteration 
'] 

我能爲了趕做'停止迭代'異常並且正常打破 循環?

下面以僞代碼的形式顯示了可能需要這種事情的一個例子。

狀態機:

s = "" 
while True : 
    if state is STATE_CODE : 
    if "//" in s : 
     tokens.add(TOKEN_COMMENT, s.split("//")[1]) 
     state = STATE_COMMENT 
    else : 
     tokens.add(TOKEN_CODE, s) 
    if state is STATE_COMMENT : 
    if "//" in s : 
     tokens.append(TOKEN_COMMENT, s.split("//")[1]) 
    else 
     state = STATE_CODE 
     # Re-evaluate same line 
     continue 
    try : 
    s = i.next() 
    except StopIteration : 
    break 
+0

S.Lott:對於狀態機,請參閱示例代碼 – grigoryvp 2009-04-13 15:19:11

+1

嗯......這不是一個合適的「do-while」;這只是一個「永遠做不到」。 「True」和「Break」有什麼不對? – 2009-04-13 15:43:48

+44

S.洛特:我很確定他的問題是關於*如何在python中實現。所以,我不希望他的代碼是完全正確的。而且,他非常接近於做......而他正在檢查「永遠」循環結束時的狀況,看看他是否應該突圍。這不是「永遠做不到」。 – Tom 2009-04-13 18:43:54

回答

646

我不確定你在做什麼。你可以實現一個do-while循環是這樣的:

while True: 
    stuff() 
    if fail_condition: 
    break 

或者:

stuff() 
while not fail_condition: 
    stuff() 

你在做什麼試圖用一個do while循環打印的東西在列表中?爲什麼不直接使用:

for i in l: 
    print i 
print "done" 

更新:

所以你有行的列表?你想繼續迭代它?如何:

for s in l: 
    while True: 
    stuff() 
    # use a "break" instead of s = i.next() 

這是否看起來像接近你想要的東西?你的代碼示例如下:

for s in some_list: 
    while True : 
    if state is STATE_CODE : 
     if "//" in s : 
     tokens.add(TOKEN_COMMENT, s.split("//")[1]) 
     state = STATE_COMMENT 
     else : 
     tokens.add(TOKEN_CODE, s) 
    if state is STATE_COMMENT : 
     if "//" in s : 
     tokens.append(TOKEN_COMMENT, s.split("//")[1]) 
     break # get next s 
     else 
     state = STATE_CODE 
     # re-evaluate same line 
     # continues automatically 
4

爲什麼你不只是做

for s in l : 
    print s 
print "done" 

+0

我需要創建一個狀態機。在狀態機中,重新評估CURRENT語句是一種正常情況,所以我需要'繼續'而不重複下一個項目。我不知道如何在'for s in l:'迭代中做這樣的事情:(在do-while循環中,'continue'會重新評估當前項目,最後迭代。 – grigoryvp 2009-04-13 06:26:30

+0

然後,你可以定義一些僞你的狀態機的代碼,所以我們可以提示你最好的pythonic解決方案嗎?我不太瞭解狀態機(可能不是唯一的),所以如果你告訴我們關於你的算法的一些信息, – Martin 2009-04-13 06:48:38

+0

添加了僞代碼示例 – grigoryvp 2009-04-13 07:29:40

26

異常會打破循環,所以你不妨在循環之外處理它。

try: 
    while True: 
    if s: 
     print s 
    s = i.next() 
except StopIteration: 
    pass 

我想,以你的代碼的問題是沒有定義的breakexcept這種行爲。通常break只上升一級,例如breaktry內部直接轉到finally(如果存在的話)出try,但不在循環之外。

相關PEP:http://www.python.org/dev/peps/pep-3136
相關問題:Breaking out of nested loops

1

看看這有助於:

設置一個標誌異常處理程序內,在S工作之前檢查它。

flagBreak = false; 
while True : 

    if flagBreak : break 

    if s : 
     print s 
    try : 
     s = i.next() 
    except StopIteration : 
     flagBreak = true 

print "done" 
25
do { 
    stuff() 
} while (condition()) 

- >

while True: 
    stuff() 
    if not condition(): 
    break 

你可以做一個函數:

def do_while(stuff, condition): 
    while condition(stuff()): 
    pass 

但 1)它是醜陋的。 2)條件應與一個參數的功能,應該由東西來填充(這是唯一的原因使用while循環經典)

15

這是一個不同的模式的一個瘋狂的解決方案 - 使用協同程序。代碼仍然非常相似,但有一個重要的區別;根本沒有退出條件!當你停止向數據提供數據時,協程(真正的協程鏈)就會停止。

def coroutine(func): 
    """Coroutine decorator 

    Coroutines must be started, advanced to their first "yield" point, 
    and this decorator does this automatically. 
    """ 
    def startcr(*ar, **kw): 
     cr = func(*ar, **kw) 
     cr.next() 
     return cr 
    return startcr 

@coroutine 
def collector(storage): 
    """Act as "sink" and collect all sent in @storage""" 
    while True: 
     storage.append((yield)) 

@coroutine  
def state_machine(sink): 
    """ .send() new parts to be tokenized by the state machine, 
    tokens are passed on to @sink 
    """ 
    s = "" 
    state = STATE_CODE 
    while True: 
     if state is STATE_CODE : 
      if "//" in s : 
       sink.send((TOKEN_COMMENT, s.split("//")[1])) 
       state = STATE_COMMENT 
      else : 
       sink.send((TOKEN_CODE, s)) 
     if state is STATE_COMMENT : 
      if "//" in s : 
       sink.send((TOKEN_COMMENT, s.split("//")[1])) 
      else 
       state = STATE_CODE 
       # re-evaluate same line 
       continue 
     s = (yield) 

tokens = [] 
sm = state_machine(collector(tokens)) 
for piece in i: 
    sm.send(piece) 

上面的代碼收集所有的令牌在tokens元組和我假定有在原來的代碼.append().add()之間沒有差別。

214

下面就來模擬do-while循環非常簡單的方法:

condition = True 
while condition: 
    # loop body here 
    condition = test_loop_condition() 
# end of loop 

一個do-while循環的主要特點是循環體總是至少執行一次,並且評估條件在循環體的底部。這裏顯示的控制結構完成了這兩個操作,不需要異常或中斷語句。它確實引入了一個額外的布爾變量。

6
while condition is True: 
    stuff() 
else: 
    stuff() 
9

了做 - 而包含循環try語句

loop = True 
while loop: 
    generic_stuff() 
    try: 
     questionable_stuff() 
#  to break from successful completion 
#  loop = False 
    except: 
     optional_stuff() 
#  to break from unsuccessful completion - 
#  the case referenced in the OP's question 
     loop = False 
    finally: 
     more_generic_stuff() 

另外,當沒有必要爲 '最終' 條款

while True: 
    generic_stuff() 
    try: 
     questionable_stuff() 
#  to break from successful completion 
#  break 
    except: 
     optional_stuff() 
#  to break from unsuccessful completion - 
#  the case referenced in the OP's question 
     break 
6

快速劈:

def dowhile(func = None, condition = None): 
    if not func or not condition: 
     return 
    else: 
     func() 
     while condition(): 
      func() 

使用方法如下:

>>> x = 10 
>>> def f(): 
...  global x 
...  x = x - 1 
>>> def c(): 
     global x 
     return x > 0 
>>> dowhile(f, c) 
>>> print x 
0 
36

我下面的代碼可能是一個有用的實施,強調之間的主要區別VS 我的理解。

因此,在這種情況下,您總是至少經歷一次循環。

first_pass = True 
while first_pass or condition: 
    first_pass = False 
    do_stuff()