web-dev-qa-db-fra.com

Python: Poursuivre jusqu'à la prochaine itération dans la boucle externe

Je voulais savoir s'il existe des moyens intégrés pour continuer à la prochaine itération en boucle externe en python. Par exemple, considérons le code:

for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            continue
    ...block1...

Je veux que cette instruction continue quitte la boucle jj et passe à l'élément suivant de la boucle ii. Je peux implémenter cette logique d'une autre manière (en définissant une variable de drapeau), mais existe-t-il un moyen simple de le faire, ou s'agit-il de demander trop?

96
Sahas
for i in ...:
    for j in ...:
        for k in ...:
            if something:
                # continue loop i

En général, lorsque vous avez plusieurs niveaux de bouclage et que break ne fonctionne pas (car vous souhaitez continuer l’une des boucles supérieures, pas celle située au-dessus de la boucle actuelle), vous pouvez effectuer l’une des opérations suivantes:

Refactoriser les boucles que vous voulez échapper dans une fonction

def inner():
    for j in ...:
        for k in ...:
            if something:
                return


for i in ...:
    inner()

L'inconvénient est que vous devrez peut-être transmettre à cette nouvelle fonction certaines variables, qui étaient auparavant dans la portée. Vous pouvez simplement les transmettre en tant que paramètres, en faire des variables d’instance sur un objet (créer un nouvel objet uniquement pour cette fonction, si elle a du sens) ou des variables globales, des singletons, peu importe (ehm, ehm).

Ou vous pouvez définir inner en tant que fonction imbriquée et le laisser capturer ce dont il a besoin (peut-être plus lent?)

for i in ...:
    def inner():
        for j in ...:
            for k in ...:
                if something:
                    return
    inner()

Utiliser des exceptions

Philosophiquement, c'est à cela que servent les exceptions, interrompant le flux de programme dans les blocs de construction structurés de la programmation (si, pour, tant que nécessaire) lorsque cela est nécessaire.

L'avantage est que vous n'avez pas à diviser le code en plusieurs parties. C'est bien si c'est une sorte de calcul que vous concevez en l'écrivant en Python. L'introduction d'abstractions à ce stade précoce peut vous ralentir.

Le problème avec cette approche est que les auteurs d'interpréteurs/compilateurs supposent généralement que les exceptions sont exceptionnelles et les optimisent en conséquence.

class ContinueI(Exception):
    pass


continue_i = ContinueI()

for i in ...:
    try:
        for j in ...:
            for k in ...:
                if something:
                    raise continue_i
    except ContinueI:
        continue

Créez une classe d'exception spéciale pour cela, afin de ne pas risquer de faire taire accidentellement une autre exception.

Quelque chose d'autre entièrement

Je suis sûr qu'il existe encore d'autres solutions.

38
user7610
for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            break
    else:
        ...block1...

Break cassera la boucle interne et block1 ne sera pas exécuté (il ne sera exécuté que si la boucle interne est sortie normalement).

119
culebrón

Dans d'autres langues, vous pouvez étiqueter la boucle et rompre avec la boucle étiquetée. La proposition d’amélioration de Python (PEP) 3136 a suggéré d’ajouter ces éléments à Python mais Guido l’a rejetée :

Cependant, je le rejette sur la base de ce code si compliqué à exiger cette fonctionnalité est très rare. Dans la plupart des cas, il existe des solutions de contournement qui produisent un code propre, par exemple, en utilisant 'return' . Bien que je sois sûr, il existe quelques cas (rares) réels où la clarté de la le code souffrirait d’une refactorisation permettant d’utiliser retour, cela est compensé par deux problèmes:

  1. La complexité ajoutée à la langue, de façon permanente. Cela n'affecte pas seulement toutes les implémentations Python, mais aussi tous les outils d’analyse de source, plus bien sûr toute la documentation pour la langue.

  2. Je m'attends à ce que le long métrage fasse l'objet d'abus plus qu'il ne le sera utilisé à droite, entraînant une nette diminution de la clarté du code (mesuré sur tout le code Python écrit désormais). Les programmeurs paresseux sont partout, et avant de vous en rendre compte, vous avez un désordre incroyable entre vos mains. code inintelligible.

Donc, si c'est ce que vous espériez ne pas avoir de chance, mais regardez l'une des autres réponses car il y a de bonnes options.

36
Dave Webb

Je pense que vous pourriez faire quelque chose comme ça:

for ii in range(200):
    restart = False
    for jj in range(200, 400):
        ...block0...
        if something:
            restart = True
            break
    if restart:
        continue
    ...block1...
11
asmeurer

Je pense que l’un des moyens les plus faciles d’y parvenir est de remplacer "continue" par "break".

for ii in range(200):
 for jj in range(200, 400):
    ...block0...
    if something:
        break
 ...block1...       

Par exemple, voici le code simple pour voir comment cela se passe exactement:

for i in range(10):
    print("doing outer loop")
    print("i=",i)
    for p in range(10):
        print("doing inner loop")
        print("p=",p)
        if p==3:
            print("breaking from inner loop")
            break
    print("doing some code in outer loop")
1
Khelina Fedorchuk

Une autre façon de traiter ce type de problème consiste à utiliser Exception ().

for ii in range(200):
    try:
        for jj in range(200, 400):
            ...block0...
            if something:
                raise Exception()
    except Exception:
        continue
    ...block1...

Par exemple:

for n in range(1,4):
    for m in range(1,4):
        print n,'-',m

résultat:

    1-1
    1-2
    1-3
    2-1
    2-2
    2-3
    3-1
    3-2
    3-3

En supposant que nous voulons sauter à la boucle n externe à partir de la boucle m si m = 3:

for n in range(1,4):
    try:
        for m in range(1,4):
            if m == 3:
                raise Exception()            
            print n,'-',m
    except Exception:
        continue

résultat:

    1-1
    1-2
    2-1
    2-2
    3-1
    3-2

Lien de référence: http://www.programming-idioms.org/idiom/42/continue-sur-loop/1264/python

1
Patrick

Nous voulons trouver quelque chose et ensuite arrêter l'itération intérieure. J'utilise un système de drapeau.

for l in f:
    flag = True
    for e in r:
        if flag==False:continue
        if somecondition:
            do_something()
            flag=False
0
Esther

Je viens de faire quelque chose comme ça. Ma solution pour cela était de remplacer l'intérieur de la boucle par une liste de compréhension. 

for ii in range(200):
    done = any([op(ii, jj) for jj in range(200, 400)])
    ...block0...
    if done:
        continue
    ...block1...

où op est un opérateur booléen agissant sur une combinaison de ii et jj. Dans mon cas, si l’une des opérations retournait vraie, c’était fini.

Ce n’est vraiment pas si différent de diviser le code en une fonction, mais j’ai pensé qu’utiliser l’opérateur "n’importe lequel" pour faire une logique OR sur une liste de booléens et que la logique dans une ligne était intéressant. Cela évite également l'appel de fonction.

0
cagem12