Pregunta

necesito para emular un bucle do-while en un programa Python. Por desgracia, el siguiente código sencillo no funciona:

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"

En lugar de "1,2,3, hecho", se imprime el siguiente resultado:

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

¿Qué puedo hacer yo con el fin de captar la 'parada iteración' excepción y romper un tiempo bucle correctamente?

Un ejemplo de por qué puede ser necesaria tal cosa se muestra a continuación como pseudocódigo.

Máquina de Estado:

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
¿Fue útil?

Solución

No estoy seguro de lo que está tratando de hacer. Se puede implementar un bucle do-while como esto:

while True:
  stuff()
  if fail_condition:
    break

O:

stuff()
while not fail_condition:
  stuff()

¿Qué haces tratando de utilizar un bucle Do While para imprimir el material en la lista? ¿Por qué no sólo tiene que utilizar:

for i in l:
  print i
print "done"

Actualización:

Así que tienes una lista de líneas? Y desea mantener la iteración a través de él? ¿Qué hay de:

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

¿Le parece como algo cercano a lo que usted quiere? Con el ejemplo de código, sería:

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

Otros consejos

Esta es una forma muy simple para emular un bucle do-while:

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

Las características principales de un bucle do-while son que el cuerpo del bucle siempre se ejecuta al menos una vez, y que la condición se evalúa en la parte inferior del cuerpo del bucle. El espectáculo estructura de control aquí logra ambas cosas sin necesidad de excepciones o romper declaraciones. Sí introduce una variable booleana adicional.

a continuación

Mi código podría ser una aplicación útil, destacando la diferencia principal entre vs como yo lo entiendo.

Así que en éste caso, siempre se pasa por el bucle al menos una vez.

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

Excepción se romperá el bucle, por lo que también podría manejarlo fuera del bucle.

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

Creo que el problema con su código es que el comportamiento de break dentro except no está definido. Generalmente break va sólo un nivel hacia arriba, por lo que, por ejemplo, break dentro try va directamente a finally (si existe) una salida de la try, pero no fuera del bucle.

PEP relacionados: http://www.python.org/dev/peps/pep -3136
pregunta relacionada: Salir de bucles anidados

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

->

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

Se puede hacer una función:

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

Sin embargo, 1) Es feo. 2) Estado debe ser una función con un parámetro, se supone que ser llenado por la materia (que es la única razón por no para utilizar el clásico bucle while.)

Aquí es una solución más loco de un patrón diferente - usando corrutinas. El código sigue siendo muy similar, pero con una diferencia importante; no hay condiciones de salida en absoluto! La co-rutina (cadena de co-rutinas en realidad) sólo se detiene cuando deja de alimentar con datos.

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)

El código anterior recoge todas las fichas como tuplas en tokens y supongo que no hay diferencia entre .append() y .add() en el código original.

La forma en que he hecho este es el siguiente ...

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

Esto me parece ser la solución simplista, me sorprende que no he visto aquí ya. Esto puede, obviamente, también puede invertir a

while not condition:

etc.

para un do - while contiene instrucciones 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()

Como alternativa, cuando no hay necesidad de la cláusula 'finalmente'

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

truco rápida:

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

Utilice este modo:

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

¿Por qué no acaba de hacer

for s in l :
    print s
print "done"

A ver si esto ayuda a:

Establecer una bandera dentro del gestor de excepciones y comprobar que antes de trabajar en el s.

flagBreak = false;
while True :

    if flagBreak : break

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

print "done"

Si estás en un escenario en el que se recorre, mientras que un recurso es Unavaliable o algo similar que se produce una excepción, usted podría utilizar algo como

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top