Pregunta Emular un ciclo do-while en Python?
Necesito emular un ciclo do-while en un programa Python. Desafortunadamente, el siguiente código directo no funciona:
l = [ 1, 2, 3 ]
i = l.__iter__()
s = None
while True :
if s :
print s
try :
s = i.next()
except StopIteration :
break
print "done"
En lugar de "1,2,3, hecho", 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 para atrapar la excepción 'detener iteración' y romper un tiempo
lazo correctamente?
Un ejemplo de por qué tal cosa puede ser necesaria se muestra a continuación como pseudocódigo.
Máquina estatal:
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
546
2018-04-13 06:18
origen
Respuestas:
No estoy seguro de lo que estás tratando de hacer. Puede implementar un ciclo do-while como este:
while True:
stuff()
if fail_condition:
break
O:
stuff()
while not fail_condition:
stuff()
¿Qué estás haciendo tratando de usar un ciclo do while para imprimir las cosas en la lista? ¿Por qué no solo usar:
for i in l:
print i
print "done"
Actualizar:
Entonces, ¿tienes una lista de líneas? ¿Y quieres seguir iterando a través de él? Qué tal si:
for s in l:
while True:
stuff()
# use a "break" instead of s = i.next()
¿Eso parece algo cercano a lo que querrías? Con su 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
703
2018-04-13 06:28
Aquí hay una forma muy simple de emular un ciclo do-while:
condition = True
while condition:
# loop body here
condition = test_loop_condition()
# end of loop
Las características clave 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. La estructura de control que se muestra aquí cumple ambos sin necesidad de excepciones o declaraciones de interrupción. Introduce una variable booleana adicional.
241
2018-03-14 00:09
Mi código a continuación podría ser una implementación útil, destacando la diferencia principal entre hacer-mientras vs mientras como yo lo entiendo
Entonces, en este caso, siempre pasas por el ciclo al menos una vez.
first_pass = True
while first_pass or condition:
first_pass = False
do_stuff()
51
2017-11-23 23:37
La excepción romperá el ciclo, por lo que también podría manejarlo fuera del ciclo.
try:
while True:
if s:
print s
s = i.next()
except StopIteration:
pass
Supongo que el problema con su código es ese comportamiento de break
dentro except
no está definido. En general break
solo sube un nivel, por ejemplo, break
dentro try
va directamente a finally
(si existe) un fuera del try
, pero no fuera del circuito.
PEP relacionado: http://www.python.org/dev/peps/pep-3136
Pregunta relacionada: Rompiendo de bucles anidados
30
2018-04-13 07:06
do {
stuff()
} while (condition())
->
while True:
stuff()
if not condition():
break
Puedes hacer una función:
def do_while(stuff, condition):
while condition(stuff()):
pass
Pero
1) Es feo
2) La condición debería ser una función con un parámetro, que se supone debe estar lleno de cosas (es la única razón no para usar el ciclo while clásico)
28
2018-04-13 13:57
Aquí hay una solución más loca de un patrón diferente: usar corutinas. El código sigue siendo muy similar, pero con una diferencia importante; no hay condiciones de salida en absoluto! La coroutine (cadena de corutinas en realidad) simplemente se detiene cuando deja de alimentarlo 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 recopila todos los tokens como tuplas en tokens
y supongo que no hay diferencia entre .append()
y .add()
en el código original.
16
2017-11-02 17:32
para un ciclo do - while que 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()
alternativamente, 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
10
2018-05-10 22:03
while condition is True:
stuff()
else:
stuff()
7
2017-11-30 01:38
Quick Hack:
def dowhile(func = None, condition = None):
if not func or not condition:
return
else:
func()
while condition():
func()
Úselo así:
>>> x = 10
>>> def f():
... global x
... x = x - 1
>>> def c():
global x
return x > 0
>>> dowhile(f, c)
>>> print x
0
6
2018-04-21 21:42
¿Por qué no lo haces?
for s in l :
print s
print "done"
?
4
2018-04-13 06:23
Vea si esto ayuda:
Establezca una bandera dentro del manejador de excepciones y revíselo antes de trabajar en la s.
flagBreak = false;
while True :
if flagBreak : break
if s :
print s
try :
s = i.next()
except StopIteration :
flagBreak = true
print "done"
1
2018-04-13 08:17