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?
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:
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()
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.
Je suis sûr qu'il existe encore d'autres solutions.
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).
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:
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.
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.
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...
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")
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
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
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.