在python中模拟do-while循环?

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

我想您的代码的问题在于没有定义except内部的break行为。一般情况下,break只上升一级,例如,try内的break直接进入finally(如果存在的话)和try外,而不是循环外。

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

上面的代码将所有令牌收集为tokens中的元组,我假设在原始代码中.append().add()之间没有区别。


对于包含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"