Emulare un ciclo do-while in Python?
-
09-09-2019 - |
Domanda
Ho bisogno di emulare un do-while in un programma Python. Purtroppo, il seguente codice semplice non funziona:
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"
Al posto di "1,2,3, fatto", stampa il seguente output:
[stdout:]1
[stdout:]2
[stdout:]3
None['Traceback (most recent call last):
', ' File "test_python.py", line 8, in <module>
s = i.next()
', 'StopIteration
']
Che cosa posso fare per intercettare l'eccezione 'arresto iterazione' e rompere un po ' ciclo correttamente?
Un esempio del perché può essere necessaria una cosa del genere è mostrato di seguito come pseudocodice.
macchina dello Stato:
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
Soluzione
Non sono sicuro di ciò che si sta cercando di fare. È possibile implementare un ciclo do-while in questo modo:
while True:
stuff()
if fail_condition:
break
o
stuff()
while not fail_condition:
stuff()
Che cosa stai facendo cercando di utilizzare un ciclo Do While per stampare la roba nella lista? Perché non basta usare:
for i in l:
print i
print "done"
Aggiornamento:
Quindi, avete un elenco di linee? E si desidera mantenere l'iterazione attraverso di essa? Che ne dite di:
for s in l:
while True:
stuff()
# use a "break" instead of s = i.next()
lo fa sembrare come qualcosa di simile a ciò che si vorrebbe? Con il vostro esempio di codice, sarebbe:
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
Altri suggerimenti
Ecco un modo molto semplice per emulare un ciclo do-while:
condition = True
while condition:
# loop body here
condition = test_loop_condition()
# end of loop
Le caratteristiche fondamentali di un ciclo do-while sono che il corpo del ciclo viene sempre eseguito almeno una volta, e che la condizione è valutata alla fine del corpo del ciclo. Lo spettacolo struttura di controllo qui realizza entrambi questi senza bisogno di eccezioni o rompere dichiarazioni. Lo fa introdurre una variabile in più booleana.
Il mio codice di seguito potrebbe essere una utile applicazione, mettendo in evidenza la differenza principale tra do-while vs mentre se ho capito bene.
Quindi, in questo caso, è sempre andare attraverso il ciclo almeno una volta.
first_pass = True
while first_pass or condition:
first_pass = False
do_stuff()
Eccezione si romperà il ciclo, in modo si potrebbe anche gestire la cosa al di fuori del ciclo.
try:
while True:
if s:
print s
s = i.next()
except StopIteration:
pass
Credo che il problema con il vostro codice è che il comportamento di break
all'interno except
non è definito. Generalmente break
va solo livello, così ad esempio break
all'interno try
va direttamente a finally
(se esiste) un fuori del try
, ma non fuori dal giro.
PEP Correlati: http://www.python.org/dev/peps/pep -3136
questione connessa: Scoppio di cicli nidificati
do {
stuff()
} while (condition())
->
while True:
stuff()
if not condition():
break
Si può fare una funzione:
def do_while(stuff, condition):
while condition(stuff()):
pass
Ma 1) E 'brutto. 2) Condizione dovrebbe essere una funzione con un parametro, dovrebbe essere riempito da cose (è l'unica ragione per non per usare il classico ciclo while.)
Ecco una soluzione più folle di un modello diverso - con coroutine. Il codice è ancora molto simile, ma con una differenza importante; non ci sono condizioni di uscita a tutti! Il coroutine (catena di coroutine veramente) si ferma solo quando si interrompe l'alimentazione con i dati.
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)
Il codice sopra raccoglie tutti i gettoni come tuple in tokens
e presumo non v'è alcuna differenza tra .append()
e .add()
nel codice originale.
Il modo in cui ho fatto questo è il seguente ...
condition = True
while condition:
do_stuff()
condition = (<something that evaluates to True or False>)
Questa mi sembra essere la soluzione semplicistica, sono sorpreso che non ho visto qui già. Questo può ovviamente anche essere invertita per
while not condition:
ecc.
per un fai - while contenente istruzioni 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()
In alternativa, quando non c'è alcun bisogno che il 'finalmente' clausola
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()
mod rapida:
def dowhile(func = None, condition = None):
if not func or not condition:
return
else:
func()
while condition():
func()
Utilizzare questo modo:
>>> x = 10
>>> def f():
... global x
... x = x - 1
>>> def c():
global x
return x > 0
>>> dowhile(f, c)
>>> print x
0
Perché non basta fare
for s in l :
print s
print "done"
Vedere se questo aiuta:
Impostare un flag all'interno del gestore di eccezioni e controllarlo prima di lavorare sulla s.
flagBreak = false;
while True :
if flagBreak : break
if s :
print s
try :
s = i.next()
except StopIteration :
flagBreak = true
print "done"
Se siete in uno scenario in cui si sta in loop mentre una risorsa è unavaliable o qualcosa di simile che genera un'eccezione, si potrebbe usare qualcosa come
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