Question

Je dois simuler une boucle do-while dans un programme Python. Malheureusement, le code simple suivant ne fonctionne pas:

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"

Au lieu de "1,2,3, fait", il imprime la sortie suivante:

[stdout:]1
[stdout:]2
[stdout:]3
None['Traceback (most recent call last):
', '  File "test_python.py", line 8, in <module>
    s = i.next()
', 'StopIteration
']

Que puis-je faire pour intercepter l'exception « itération stop » et de briser un certain temps boucle correctement?

Un exemple de pourquoi une telle chose peut être nécessaire est indiquée ci-dessous comme pseudo-code.

La machine d'état:

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
Était-ce utile?

La solution

Je ne sais pas ce que vous essayez de faire. Vous pouvez mettre en œuvre une boucle do-while comme ceci:

while True:
  stuff()
  if fail_condition:
    break

Ou:

stuff()
while not fail_condition:
  stuff()

Que faites-vous essayer d'utiliser un do while pour imprimer la substance dans la liste? Pourquoi ne pas simplement utiliser:

for i in l:
  print i
print "done"

Mise à jour:

Alors avez-vous une liste de lignes? Et vous voulez garder itérer à travers elle? Que diriez-vous:

for s in l: 
  while True: 
    stuff() 
    # use a "break" instead of s = i.next()

Est-ce que quelque chose semble proche de ce que vous voulez? Avec votre exemple de code, ce serait:

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

Autres conseils

Voici un moyen très simple d'imiter une boucle do-while:

condition = True
while condition:
    # loop body here
    condition = test_loop_condition()
# end of loop

Les principales caractéristiques d'une boucle do-while sont que le corps de la boucle exécute toujours au moins une fois, et que la condition est évaluée au bas du corps de la boucle. La structure de contrôle spectacle accomplit ici ces deux sans avoir besoin d'exceptions ou de casser des déclarations. Il n'introduit une variable booléenne supplémentaire.

Mon code ci-dessous pourrait être une mise en œuvre utile, en soulignant la principale différence entre vs si je comprends bien.

Donc, dans ce un cas, vous allez toujours à travers la boucle au moins une fois.

first_pass = True
while first_pass or condition:
    first_pass = False
    do_stuff()

Exception cassera la boucle, alors vous pourriez aussi bien gérer en dehors de la boucle.

try:
  while True:
    if s:
      print s
    s = i.next()
except StopIteration:   
  pass

Je suppose que le problème avec votre code est que le comportement de l'intérieur break except n'est pas défini. En général, break va un seul niveau, donc par exemple break l'intérieur try va directement à finally (si elle existe) une sortie de la try, mais pas hors de la boucle.

PEP connexes: http://www.python.org/dev/peps/pep -3136
question connexe: rupture de boucles imbriquées

do {
  stuff()
} while (condition())

->

while True:
  stuff()
  if not condition():
    break

Vous pouvez faire une fonction:

def do_while(stuff, condition):
  while condition(stuff()):
    pass

1) Il est laid. 2) Etat doit être une fonction avec un paramètre, censé être rempli par la substance (c'est la seule raison pour pas pour utiliser le classique en boucle.)

Voici une solution plus fou d'un modèle différent - en utilisant coroutines. Le code est encore très similaire, mais avec une différence importante; il n'y a pas de conditions de sortie du tout! La coroutine (chaîne de coroutines vraiment) arrête juste quand vous arrêtez de le nourrir avec des données.

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)

Le code ci-dessus recueille tous les jetons que tuples dans tokens et je suppose qu'il n'y a pas de différence entre .append() et .add() dans le code d'origine.

La façon dont je l'ai fait comme suit ...

condition = True
while condition:
     do_stuff()
     condition = (<something that evaluates to True or False>)

Cela me semble être la solution simpliste, je suis surpris que je ne l'ai pas vu ici déjà. Cela peut évidemment être inversée à

while not condition:

etc.

pour un do - while contenant des instructions 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()

alternativement, quand il n'y a pas besoin de la clause « enfin »

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()

hack:

def dowhile(func = None, condition = None):
    if not func or not condition:
        return
    else:
        func()
        while condition():
            func()

Utilisez comme ceci:

>>> x = 10
>>> def f():
...     global x
...     x = x - 1
>>> def c():
        global x
        return x > 0
>>> dowhile(f, c)
>>> print x
0

Pourquoi ne faites-vous pas juste

for s in l :
    print s
print "done"

Voyez si cela aide:

Définir un indicateur dans le gestionnaire d'exception et vérifier avant de travailler sur le s.

flagBreak = false;
while True :

    if flagBreak : break

    if s :
        print s
    try :
        s = i.next()
    except StopIteration :
        flagBreak = true

print "done"

Si vous êtes dans un scénario où vous Looping alors qu'une ressource est unavaliable ou quelque chose de similaire qui lance une exception, vous pouvez utiliser quelque chose comme

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top