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
È stato utile?

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 vs 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top