Emulieren eine do-while-Schleife in Python?
-
09-09-2019 - |
Frage
Ich brauche eine do-while-Schleife in einem Python-Programm zu emulieren. Leider ist die folgende einfache Code nicht:
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"
Anstelle von "1,2,3, getan", druckt es die folgende Ausgabe:
[stdout:]1
[stdout:]2
[stdout:]3
None['Traceback (most recent call last):
', ' File "test_python.py", line 8, in <module>
s = i.next()
', 'StopIteration
']
Was kann ich tun, um die ‚Stop-Iteration‘ Ausnahme zu fangen und eine Weile zu brechen Schleife richtig?
Ein Beispiel, warum eine solche Sache erforderlich sein kann, so wie Pseudo-Code dargestellt ist.
Die Zustandsmaschine:
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
Lösung
Ich bin nicht sicher, was Sie zu tun versuchen. Sie können eine do-while-Schleife wie folgt implementieren:
while True:
stuff()
if fail_condition:
break
Oder:
stuff()
while not fail_condition:
stuff()
Was tun Sie versuchen, eine do zu verwenden, während Schleife, um die Sachen in der Liste zu drucken? Warum nicht einfach verwenden:
for i in l:
print i
print "done"
Update:
So haben Sie eine Liste der Linien haben? Und Sie wollen durch Iterieren halten? Wie wäre es:
for s in l:
while True:
stuff()
# use a "break" instead of s = i.next()
Heißt das, wie in der Nähe etwas scheinen, was Sie wollen? Mit Ihrem Codebeispiel wäre es:
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
Andere Tipps
Hier ist eine sehr einfache Möglichkeit, eine do-while-Schleife zu emulieren:
condition = True
while condition:
# loop body here
condition = test_loop_condition()
# end of loop
Die wichtigsten Merkmale einer do-while-Schleife sind, dass der Schleifenkörper immer mindestens einmal ausgeführt wird, und dass die Bedingung ist an der Unterseite des Schleifenkörpers ausgewertet. Die Steuerstruktur zeigen leistet hier diese beiden ohne die Notwendigkeit für Ausnahmen oder Aussagen brechen. Es macht eine zusätzliche Boolesche Variable einzuführen.
Mein Code unten könnte eine nützliche Implementierung sein, den Hauptunterschied zwischen Hervorhebung do-while vs während getaggt wie ich es verstehe.
So in diesem Fall, können Sie immer durch die Schleife gehen mindestens einmal.
first_pass = True
while first_pass or condition:
first_pass = False
do_stuff()
Eine Ausnahme ist die Schleife brechen, so dass Sie könnte es auch behandeln außerhalb der Schleife.
try:
while True:
if s:
print s
s = i.next()
except StopIteration:
pass
Ich denke, dass das Problem mit Ihrem Code, dass das Verhalten von break
ist innerhalb except
nicht definiert ist. Im Allgemeinen break
geht nur eine Ebene nach oben, so z.B. break
innerhalb try
direkt an finally
geht einem aus dem try
(falls vorhanden), aber nicht aus der Schleife.
Einschlägige PEP: http://www.python.org/dev/peps/pep -3136
Verwandte Frage: Ausbrechen von verschachtelten Schleifen
do {
stuff()
} while (condition())
->
while True:
stuff()
if not condition():
break
Sie können eine Funktion tun:
def do_while(stuff, condition):
while condition(stuff()):
pass
Aber 1) Es ist hässlich. 2) Bedingung eine Funktion mit einem Parameter sein soll, sollte von Sachen gefüllt werden (es ist der einzige Grund, nicht verwenden, um die klassischen while-Schleife.)
Hier ist eine verrückte Lösung aus einem anderen Muster - mit Koroutinen. Der Code ist noch sehr ähnlich, aber mit einem wichtigen Unterschied; gibt es überhaupt keine Austrittsbedingungen! Die Koroutine (Kette der Koroutinen wirklich) nur stoppen, wenn Sie es mit Daten zu stoppen Fütterung.
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)
Der obige Code sammelt alle Tokens als Tupel in tokens
und ich nehme an, es gibt keinen Unterschied zwischen .append()
und .add()
im ursprünglichen Code.
So wie ich das getan habe, ist wie folgt ...
condition = True
while condition:
do_stuff()
condition = (<something that evaluates to True or False>)
Das scheint mir die vereinfachende Lösung zu sein, ich bin überrascht, ich habe es hier nicht schon gesehen. Dies kann natürlich auch umgekehrt werden,
while not condition:
etc.
für ein do - while-Schleife enthält try-Anweisungen
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()
alternativ, wenn es keine Notwendigkeit für den ‚endlich‘ -Klausel
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()
Schnell Hack:
def dowhile(func = None, condition = None):
if not func or not condition:
return
else:
func()
while condition():
func()
Verwenden Sie wie folgt:
>>> x = 10
>>> def f():
... global x
... x = x - 1
>>> def c():
global x
return x > 0
>>> dowhile(f, c)
>>> print x
0
Warum gehst du nicht einfach tun
for s in l :
print s
print "done"
Sehen Sie, ob das hilft:
Stellen Sie eine Flagge in der Exception-Handler und überprüfen sie, bevor sie auf dem s arbeiten.
flagBreak = false;
while True :
if flagBreak : break
if s :
print s
try :
s = i.next()
except StopIteration :
flagBreak = true
print "done"
Wenn Sie in einem Szenario sind, wo Sie Looping, während eine Ressource unavaliable oder etwas ähnliches ist, die eine Ausnahme auslöst, Sie so etwas wie
verwenden könnteimport 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