Emulate a do-while loop in Python?
我需要在Python程序中模拟do-while循环。不幸的是,以下简单的代码不起作用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | list_of_ints = [ 1, 2, 3 ] iterator = list_of_ints.__iter__() element = None while True: if element: print element try: element = iterator.next() except StopIteration: break print"done" |
它不是"1,2,3,完成",而是打印以下输出:
1 2 3 4 5 6 7 8 | [stdout:]1 [stdout:]2 [stdout:]3 None['Traceback (most recent call last): ', ' File"test_python.py", line 8, in <module> s = i.next() ', 'StopIteration '] |
我该怎么做才能捕获"停止迭代"异常并中断一段时间正确循环?
下面以伪代码的形式展示了为什么需要这样的东西。
状态机:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 |
我不知道你想做什么。您可以实现这样的do-while循环:
1 2 3 4 | while True: stuff() if fail_condition: break |
或:
1 2 3 | stuff() while not fail_condition: stuff() |
你想用do while循环打印列表中的内容吗?为什么不直接使用:
1 2 3 | for i in l: print i print"done" |
更新:
那么你有一个行列表吗?你想一直重复一遍吗?怎么样:
1 2 3 4 | for s in l: while True: stuff() # use a"break" instead of s = i.next() |
这看起来像是你想要的吗?对于您的代码示例,它将是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
下面是一个非常简单的模拟do-while循环的方法:
1 2 3 4 5 | condition = True while condition: # loop body here condition = test_loop_condition() # end of loop |
do-while循环的主要特性是循环体始终至少执行一次,并且在循环体的底部评估条件。这里显示的控制结构可以实现这两种功能,不需要异常或中断语句。它确实引入了一个额外的布尔变量。
下面的代码可能是一个有用的实现,它强调了do-while和while之间的主要区别,正如我理解的那样。
所以在这个例子中,你总是至少经历一次循环。
1 2 3 4 | first_pass = True while first_pass or condition: first_pass = False do_stuff() |
异常将中断循环,因此您也可以在循环之外处理它。
1 2 3 4 5 6 7 | try: while True: if s: print s s = i.next() except StopIteration: pass |
我想您的代码的问题在于没有定义
相关PEP:http://www.python.org/dev/peps/pep-3136
相关问题:突破嵌套循环
1 2 3 | do { stuff() } while (condition()) |
>
1 2 3 4 | while True: stuff() if not condition(): break |
您可以执行以下操作:
1 2 3 | def do_while(stuff, condition): while condition(stuff()): pass |
但是1)它很丑。2)条件应该是一个带有一个参数的函数,应该由填充物填充(这是不使用经典while循环的唯一原因)。
这里有一个不同模式的更疯狂的解决方案——使用协同程序。代码仍然非常相似,但有一个重要区别:根本没有退出条件!协程(真正的协程链)只是在您停止向它提供数据时停止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 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) |
上面的代码将所有令牌收集为
对于包含try语句的do-while循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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() |
或者,当不需要"finally"条款时
1 2 3 4 5 6 7 8 9 10 11 | 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 |
我这样做的方式如下…
1 2 3 4 | condition = True while condition: do_stuff() condition = (<something that evaluates to True or False>) |
在我看来,这似乎是一个简单的解决方案,我很惊讶我还没有在这里看到它。这显然也可以颠倒为
1 | while not condition: |
等。
快速破解:
1 2 3 4 5 6 7 | def dowhile(func = None, condition = None): if not func or not condition: return else: func() while condition(): func() |
使用如下:
1 2 3 4 5 6 7 8 9 10 | >>> x = 10 >>> def f(): ... global x ... x = x - 1 >>> def c(): global x return x > 0 >>> dowhile(f, c) >>> print x 0 |
1 2 3 4 | while condition is True: stuff() else: stuff() |
你为什么不这么做?
1 2 3 | for s in l : print s print"done" |
?
如果您在一个资源不可用或类似情况下循环,从而引发异常,那么可以使用
1 2 3 4 5 6 7 8 9 10 | import time while True: try: f = open('some/path', 'r') except IOError: print('File could not be read. Retrying in 5 seconds') time.sleep(5) else: break |
看看这是否有帮助:
在异常处理程序内设置一个标志,并在处理S之前检查它。
1 2 3 4 5 6 7 8 9 10 11 12 13 | flagBreak = false; while True : if flagBreak : break if s : print s try : s = i.next() except StopIteration : flagBreak = true print"done" |