Эмулировать цикл do-while в Python?

Мне нужно эмулировать цикл do-while в программе Python. К сожалению, следующий простой код не работает:

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, done" он печатает следующий результат:

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

Что я могу сделать, чтобы поймать исключение "стоп итерации" и правильно разогнать цикл while?

Пример того, почему такая вещь может понадобиться, показана ниже как псевдокод.

Государственный аппарат:

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

Ответ 1

Я не уверен, что вы пытаетесь сделать. Вы можете реализовать цикл do-while следующим образом:

while True:
  stuff()
  if fail_condition:
    break

Или:

stuff()
while not fail_condition:
  stuff()

Что вы пытаетесь использовать цикл 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

Ответ 2

Здесь очень простой способ эмулировать цикл do-while:

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

Ключевыми особенностями цикла do-while являются то, что тело цикла всегда выполняется хотя бы один раз и что условие оценивается в нижней части тела цикла. Представленная здесь структура управления выполняет обе эти функции без необходимости исключений или инструкций break. Он вводит одну дополнительную логическую переменную.

Ответ 3

Моим приведенным ниже кодом может быть полезная реализация, подчеркивающая основное различие между vs как я понимаю.

Итак, в этом случае вы всегда проходите цикл по крайней мере один раз.

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

Ответ 4

Исключение будет прерывать цикл, поэтому вы можете также обрабатывать его за пределами цикла.

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

Я думаю, что проблема с вашим кодом заключается в том, что поведение break внутри, except, не определено. Обычно break идет только на один уровень вверх, поэтому, например, break внутри try идет непосредственно, finally (если он существует) из try, но не из цикла.

Связанный PEP: http://www.python.org/dev/peps/pep-3136
Связанный вопрос: Разрыв вложенных циклов

Ответ 5

do {
  stuff()
} while (condition())

- >

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

Вы можете выполнить функцию:

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

Но 1) Это некрасиво. 2) Условие должно быть функцией с одним параметром, который должен быть заполнен материалом (это единственная причина не использовать классический цикл while).

Ответ 6

Вот более сумасшедшее решение другого шаблона - с помощью сопрограмм. Код по-прежнему очень похож, но с одним важным отличием; нет никаких условий выхода! Корутин (цепочка сопрограмм на самом деле) просто останавливается, когда вы перестаете кормить его данными.

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

Ответ 7

для цикла do-while, содержащего утверждения 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 question
        loop = False
   finally:
        more_generic_stuff()

в качестве альтернативы, когда нет необходимости в разделе "finally"

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 question
        break

Ответ 8

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

Ответ 9

Быстрый взлом:

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

Ответ 10

Почему бы вам просто не сделать

for s in l :
    print s
print "done"

?

Ответ 11

То, как я это сделал, выглядит следующим образом...

condition = True
while condition:
     do_stuff()
     condition = (<something that evaluates to True or False>)

Мне кажется, что это упрощенное решение, я удивлен, что я не видел его здесь уже. Это, очевидно, также может быть инвертировано

while not condition:

и т.п.

Ответ 12

Посмотрите, поможет ли это:

Установите флаг внутри обработчика исключений и проверьте его перед работой над s.

flagBreak = false;
while True :

    if flagBreak : break

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

print "done"

Ответ 13

Если вы находитесь в сценарии, в котором вы зацикливаете, пока ресурс недоступен или что-то подобное, что вызывает исключение, вы можете использовать что-то вроде

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