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
War es hilfreich?

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 vs 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önnte
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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top