Вопрос

Мне нужно эмулировать цикл 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,готово» он печатает следующий вывод:

[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
Это было полезно?

Решение

Я не уверен, что вы пытаетесь сделать.Вы можете реализовать цикл 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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

->

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

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

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

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

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

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() в исходном коде.

Я сделал это следующим образом...

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

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

while not condition:

и т. д.

для цикла 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'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
while condition is True: 
  stuff()
else:
  stuff()

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

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

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

for s in l :
    print s
print "done"

?

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

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

flagBreak = false;
while True :

    if flagBreak : break

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

print "done"

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

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top