Come uscire da più loop?


481

Dato il seguente codice (che non funziona):

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break 2 #this doesn't work :(
        if ok.lower() == "n": break
    #do more processing with menus and stuff

C'è un modo per farlo funzionare? O devo fare un controllo per uscire dal ciclo di input, poi un altro, più limitato, controllare nel ciclo esterno per interrompere tutti insieme se l'utente è soddisfatto?


87
Perché Python non ha solo 'break (n)' dove n è il numero di livelli da cui vuoi uscire.
Nathan,

2
Il C ++ è bello qui gotose sei immerso in un sacco di cicli
Drake Johnson,

Risposte:


512

Il mio primo istinto sarebbe di trasformare il loop nidificato in una funzione e usarlo returnper scoppiare.


3
Questo è un altro pensiero che avevo, dal momento che una funzione get_input_yn () sarebbe utile anche altrove, ne sono certa.
Matthew Scharley,

96
concordato in questo caso specifico, ma nel caso generale del refactoring "I loop nidificati, cosa devo fare" potrebbe non avere senso.
quick_dry

usare un'eccezione può essere più semplice quando devi cedere invece di usare return, tuttavia in questo caso dovresti probabilmente usare itertools.islice ().
Robert King,

5
Di solito è possibile riformattare il loop interno nel proprio metodo, che restituisce true per continuare, false per interrompere il loop esterno. while condition1: / if not MyLoop2 (params): break. Un'alternativa è impostare una bandiera booleana, che viene testata su entrambi i livelli. more = True / while condition1 e more: / while condition2 e more: / if stopCondition: more = False / break / ...
ToolmakerSteve

7
Concordo sul fatto che sforzarsi di usare returnsia l'approccio giusto. E il ragionamento è che, secondo lo Zen di Python , "flat è meglio di nidificato". Abbiamo tre livelli di annidamento qui e se ciò inizia a intromettersi, è tempo di ridurre l'annidamento o almeno estrarre l'intero annidamento in una funzione a sé stante.
Lutz Prechelt,

240

Ecco un altro approccio breve. Lo svantaggio è che puoi solo interrompere il circuito esterno, ma a volte è esattamente quello che vuoi.

for a in xrange(10):
    for b in xrange(20):
        if something(a, b):
            # Break the inner loop...
            break
    else:
        # Continue if the inner loop wasn't broken.
        continue
    # Inner loop was broken, break the outer.
    break

Questo utilizza il costrutto for / else spiegato in: Perché Python usa 'else' dopo e per i cicli while?

Informazioni chiave: sembra solo che il ciclo esterno si interrompa sempre. Ma se il circuito interno non si interrompe, neanche il circuito esterno.

La continuedichiarazione è la magia qui. È nella clausola for-else. Per definizione ciò accade se non c'è interruzione interiore. In quella situazione continueelude ordinatamente la rottura esterna.


6
@eugeney Perché no? La prima pausa uscirà dal circuito interno.
Navin,

5
@eugeney Mi sento come se mi mancasse qualcosa qui. Puoi pubblicare un esempio?
Navin,

4
@Mingliang che può andare prima di continuare.
Baldrickk,

1
Ottenuto da un video di Raymond Hettinger, youtu.be/OSGv2VnC0go?t=971 , leggi le dichiarazioni "else" allegate per i loop come "no_break", quindi diventa più facile da capire.
Ambareesh,

2
Questo è intelligente. :-) Tuttavia, non semplice. Francamente, non sono convinto dagli argomenti per mantenere etichettati break o break (n) fuori da Python. Le soluzioni alternative aggiungono più complessità.
rfportilla,

148

PEP 3136 propone break / continue etichettato. Guido lo respinse perché "il codice così complicato da richiedere questa funzione è molto raro". Il PEP menziona alcune soluzioni alternative (come la tecnica dell'eccezione), mentre Guido ritiene che il refactoring per utilizzare il ritorno sarà più semplice nella maggior parte dei casi.


73
Anche se refactor / returnè generalmente la strada da percorrere, ho visto parecchi casi in cui una semplice ' break 2' frase concisa avrebbe semplicemente molto senso. Inoltre, refactor / returnnon funziona allo stesso modo per continue. In questi casi, l'interruzione numerica e il proseguimento sarebbero più facili da seguire e meno ingombranti rispetto al refactoring di una minuscola funzione, aumentando le eccezioni o la logica contorta che comporta l'impostazione di un flag per rompersi ad ogni livello del nido. È un peccato che Guido l'abbia respinto.
James Haigh,

10
break; breaksarebbe bello.
PyRulez,

5
@Jeyekomon Il problema è che non hai bisogno di 3 o più loop nidificati perché questo sia un problema. 2 loop nidificati sono piuttosto comuni
Jon

6
"Il codice così complicato da richiedere questa funzione è molto raro". Ma se si utilizza mai un codice così complicato, la mancanza di loop etichettati lo renderà ancora più complicato, poiché è necessario inoltrare manualmente breaktutti i loop. Stupido.
BallpointBen,

3
Apparentemente, posso solo modificare un post per 5 minuti (sono state le 6). Quindi, ecco il mio post modificato: I miei 2 centesimi: Perl ha etichettato break (ma lo chiama "last") e "next" per procedere direttamente alla successiva iterazione. Non è affatto raro, lo uso sempre. Sono nuovo di zecca per Python e ne ho già bisogno. Inoltre, le interruzioni numerate sarebbero orribili per il refactoring: meglio etichettare il loop da cui si desidera interrompere, quindi utilizzare break <label> per indicare esplicitamente da quale loop si desidera interrompere.
John Deighan,

119

Innanzitutto, la logica ordinaria è utile.

Se, per qualche motivo, le condizioni di terminazione non possono essere risolte, le eccezioni sono un piano di fallback.

class GetOutOfLoop( Exception ):
    pass

try:
    done= False
    while not done:
        isok= False
        while not (done or isok):
            ok = get_input("Is this ok? (y/n)")
            if ok in ("y", "Y") or ok in ("n", "N") : 
                done= True # probably better
                raise GetOutOfLoop
        # other stuff
except GetOutOfLoop:
    pass

Per questo esempio specifico, potrebbe non essere necessaria un'eccezione.

D'altra parte, spesso abbiamo le opzioni "Y", "N" e "Q" nelle applicazioni in modalità personaggio. Per l'opzione "Q", vogliamo un'uscita immediata. È più eccezionale.


4
Scherzi a parte, le eccezioni sono estremamente economiche e il pitone idiomatico ne usa molte e molte. È molto facile definire e lanciare anche quelli personalizzati.
Gregg Lind,

13
Idea interessante. Sono lacerato se amarlo o odiarlo.
Craig McQueen,

8
Questa soluzione sarebbe più utile se mostrasse le due varianti separatamente. (1) usando un flag ( done). (2) sollevare un'eccezione. Unendoli insieme in un'unica soluzione lo rende complicato. Per i futuri lettori: TUTTO usa tutte le linee che coinvolgono done, OPPURE definire GetOutOfLoop(Exception)e aumentare / tranne quello.
ToolmakerSteve

4
In generale, l'utilizzo di try-block per qualsiasi altra cosa, tranne le eccezioni, è molto disapprovato. I blocchi di prova sono specificamente progettati per la gestione degli errori e il loro utilizzo per uno strano flusso di controllo non è molto buono, dal punto di vista stilistico.
nobillygreen,

3
@ tommy.carstensen Questa è una sciocchezza; sia la definizione di una nuova sottoclasse di eccezioni sia l'innalzamento (come mostrato nella risposta) e il passaggio di un messaggio personalizzato al Exceptioncostruttore (ad es. raise Exception('bla bla bla')) sono validi sia in Python 2 che in Python 3. Il primo è preferibile in questo caso perché non vogliamo il nostro exceptblocco per catturare tutte le eccezioni, ma solo l'eccezione speciale che stiamo usando per uscire dal loop. Se facciamo le cose come suggerisci tu, e quindi un bug nel nostro codice provoca un'eccezione imprevista, verrà erroneamente trattata allo stesso modo di uscire deliberatamente dal ciclo.
Mark Amery,

54

Tendo a concordare sul fatto che il refactoring in una funzione è di solito l'approccio migliore per questo tipo di situazione, ma per quando è davvero necessario uscire dai loop annidati, ecco una variante interessante dell'approccio di aumento delle eccezioni descritto da @ S.Lott. Usa l' withaffermazione di Python per rendere un po 'più piacevole l'eccezione dell'eccezione. Definisci un nuovo gestore di contesto (devi farlo una sola volta) con:

from contextlib import contextmanager
@contextmanager
def nested_break():
    class NestedBreakException(Exception):
        pass
    try:
        yield NestedBreakException
    except NestedBreakException:
        pass

Ora puoi utilizzare questo gestore di contesto come segue:

with nested_break() as mylabel:
    while True:
        print "current state"
        while True:
            ok = raw_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": raise mylabel
            if ok == "n" or ok == "N": break
        print "more processing"

Vantaggi: (1) è leggermente più pulito (nessun blocco try-tranne esplicito) e (2) si ottiene una Exceptionsottoclasse su misura per ogni uso di nested_break; non è necessario dichiarare la propria Exceptionsottoclasse ogni volta.


40

Innanzitutto, potresti anche considerare di rendere una funzione il processo di ottenere e validare l'input; all'interno di quella funzione, puoi semplicemente restituire il valore se è corretto e continuare a girare nel ciclo while in caso contrario. Questo essenzialmente elimina il problema che hai risolto e di solito può essere applicato nel caso più generale (interruzione di più loop). Se devi assolutamente mantenere questa struttura nel tuo codice, e davvero non vuoi occuparti dei booleani di contabilità ...

Puoi anche usare goto nel modo seguente (usando un modulo Pesce d'aprile da qui ):

#import the stuff
from goto import goto, label

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": goto .breakall
        if ok == "n" or ok == "N": break
    #do more processing with menus and stuff
label .breakall

Lo so, lo so, "non usare goto" e tutto il resto, ma funziona bene in strani casi come questo.


1
Se è qualcosa come il comando COME FROM in INTERCAL, allora niente
1800 INFORMAZIONI

3
mi piace lo scherzo, ma il punto di overflow dello stack è quello di promuovere un buon codice, quindi devo votare verso il basso :(
Christian Oudard,

13
Penso che sia una soluzione abbastanza chiara e leggibile per qualificarsi come un buon codice, quindi lo voto. :)
JT Hurley il

1
@JTHurley no, questo non è pulito e leggibile. Voglio dire, può sembrare pulito e leggibile in questo esempio, ma in qualsiasi scenario di vita reale andiamo a creare un pasticcio sacro . (Anche questo è tremendamente anti-pitonico ...)
Alois Mahdal,

2
goto ottiene una cattiva reputazione, qualsiasi programmatore professionista dovrebbe essere in grado di gestirlo correttamente secondo me.
Albert Renshaw, l'

33

Introduci una nuova variabile che utilizzerai come "interruzione di circuito". Prima assegna qualcosa ad esso (False, 0, ecc.), Quindi, all'interno del loop esterno, prima di interrompere da esso, cambia il valore in qualcos'altro (True, 1, ...). Una volta terminato il ciclo, verifica il ciclo "parent" per quel valore. Lasciami dimostrare:

breaker = False #our mighty loop exiter!
while True:
    while True:
        if conditionMet:
            #insert code here...
            breaker = True 
            break
    if breaker: # the interesting part!
        break   # <--- !

Se hai un ciclo infinito, questa è l'unica via d'uscita; per altri loop, l'esecuzione è molto più veloce. Questo funziona anche se hai molti loop nidificati. Puoi uscire da tutto o solo da pochi. Possibilità infinite! Spero che questo abbia aiutato!


22

Per uscire da più loop nidificati, senza eseguire il refactoring in una funzione, utilizzare una "istruzione goto simulata" con l' eccezione StopIteration integrata :

try:
    for outer in range(100):
        for inner in range(100):
            if break_early():
                raise StopIteration

except StopIteration: pass

Vedi questa discussione sull'uso delle dichiarazioni goto per uscire dai loop nidificati.


1
Sembra molto più bello che creare la tua classe per gestire l'eccezione e sembra molto pulito. C'è qualche motivo per cui non dovrei farlo?
mgjk,

In effetti StopIteration sta usando per i generatori, ma penso che normalmente non ci siano eccezioni StopIteration non corrispondenti. Quindi sembra una buona soluzione, ma non c'è comunque alcun errore nel creare una nuova eccezione.
Kowalski il

1
La soluzione migliore e più semplice per me
Alexandre Huat,

16

keeplooping=True
while keeplooping:
    #Do Stuff
    while keeplooping:
          #do some other stuff
          if finisheddoingstuff(): keeplooping=False

o qualcosa di simile. È possibile impostare una variabile nel loop interno e controllarla nel loop esterno immediatamente dopo l'uscita del loop interno, interrompendo se appropriato. Mi piace un po 'il metodo GOTO, a condizione che non ti dispiaccia usare un modulo joke di April Fool - non è Pythonic, ma ha senso.


questa è una sorta di impostazione della bandiera!
SIslam,

Penso che sia un'ottima soluzione.
Kowalski il

13

Questo non è il modo più carino per farlo, ma secondo me è il modo migliore.

def loop():
    while True:
    #snip: print out current state
        while True:
            ok = get_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": return
            if ok == "n" or ok == "N": break
        #do more processing with menus and stuff

Sono abbastanza sicuro che potresti risolvere qualcosa usando anche la ricorsione qui, ma non so se sia una buona opzione per te.


Questa è stata la soluzione giusta per me. Il mio caso d'uso era molto diverso da quello dei PO. Stavo ripetutamente eseguendo il ciclo sugli stessi dati due volte per trovare permutazioni, quindi non volevo separare i due mentre i loop.
Brian Peterson,

9

E perché non continuare a ripetere il ciclo se due condizioni sono vere? Penso che questo sia un modo più pitonico:

dejaVu = True

while dejaVu:
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y" or ok == "n" or ok == "N":
            dejaVu = False
            break

No?

Ti auguro il meglio.


perché non solo while dejaVu:? Lo hai impostato su true comunque.
Matthew Scharley,

ehi che funziona! Stavo pensando in due Truecondizioni a saltare due loop, ma solo uno è sufficiente.
Mauro Aspé,

2
@MatthewScharley Penso che questo sia per dimostrare che funziona in loop nidificati.
gestire il

@ MauroAspé questo non farà esattamente ciò che richiede l'OP. eseguirà comunque l'intero ciclo esterno ma l'obiettivo è che se si interrompe il resto del codice non verrà eseguito
yamm

@yamm Potrebbe non essere risolto con a if not dejaVu: breaknella parte inferiore e quindi uscire dal ciclo principale? Penso che la soluzione sia la più vicina a ciò che è stato chiesto. +1
milcak,

8

Fattorizza la tua logica di loop in un iteratore che produce le variabili di loop e restituisce una volta terminato: ecco un semplice che delinea le immagini in righe / colonne fino a quando non siamo fuori dalle immagini o fuori dai luoghi per metterle:

def it(rows, cols, images):
    i = 0
    for r in xrange(rows):
        for c in xrange(cols):
            if i >= len(images):
                return
            yield r, c, images[i]
            i += 1 

for r, c, image in it(rows=4, cols=4, images=['a.jpg', 'b.jpg', 'c.jpg']):
    ... do something with r, c, image ...

Questo ha il vantaggio di dividere la complicata logica del loop e l'elaborazione ...


3

In questo caso, come sottolineato anche da altri, la decomposizione funzionale è la strada da percorrere. Codice in Python 3:

def user_confirms():
    while True:
        answer = input("Is this OK? (y/n) ").strip().lower()
        if answer in "yn":
            return answer == "y"

def main():
    while True:
        # do stuff
        if user_confirms():
            break

3

C'è un trucco nascosto nella while ... elsestruttura di Python che può essere usato per simulare la doppia interruzione senza molte modifiche / aggiunte al codice. In sostanza se la whilecondizione è falsa, il elseblocco viene attivato. Né eccezioni, continuebreakattivare il elseblocco. Per ulteriori informazioni, consultare le risposte a " Clausola Else su Python while statement " o Python doc su while (v2.7) .

while True:
    #snip: print out current state
    ok = ""
    while ok != "y" and ok != "n":
        ok = get_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N":
            break    # Breaks out of inner loop, skipping else

    else:
        break        # Breaks out of outer loop

    #do more processing with menus and stuff

L'unico aspetto negativo è che è necessario spostare la condizione di doppia interruzione nella whilecondizione (o aggiungere una variabile flag). Variazioni di questo esistono anche per il forloop, in cui il elseblocco viene attivato dopo il completamento del loop.


Ciò non sembra soddisfare i requisiti delle doppie interruzioni. Funziona esattamente per il problema indicato, ma non per la domanda effettiva.
Dakkaron,

@Dakkaron Sei sicuro di aver compreso correttamente il codice? Il codice risolve davvero la domanda dei PO e si interrompe in modo simile alla richiesta. Tuttavia, non esce da più loop, ma utilizza la clausola else per sostituire la necessità di raddoppiare l'interruzione.
holroy,

Dalla mia comprensione la domanda era How to break out of multiple loops in Python?e la risposta avrebbe dovuto essere "Non funziona, prova qualcos'altro". So che risolve l'esatto esempio dell'OP, ma non risponde alla loro domanda.
Dakkaron,

@Dakkaron, vedi la descrizione del problema sotto il codice e, a mio avviso, risponde davvero alla domanda dei PO.
holroy,

2

Un altro modo per ridurre la tua iterazione in un ciclo a livello singolo sarebbe tramite l'uso di generatori come specificato anche nel riferimento di Python

for i, j in ((i, j) for i in A for j in B):
    print(i , j)
    if (some_condition):
        break

Potresti ridimensionarlo a qualsiasi numero di livelli per il loop

Il rovescio della medaglia è che non è più possibile interrompere solo un singolo livello. È tutto o niente.

Un altro aspetto negativo è che non funziona con un ciclo while. Inizialmente volevo pubblicare questa risposta su Python: `spezzare` da tutti i loop ma sfortunatamente è chiuso come duplicato


1
Funziona anche per i cicli while, devi solo scrivere il tuo generatore come def (con resa), non come comprensione.
Veky,

Sì, un oratore di un PyCon afferma che anche la risposta accettata da @ RobertRossney non è veramente Pythonic, ma un generatore è il modo giusto per interrompere più loop. (Consiglio di guardare l'intero video!)
Post169

2

La mia ragione per venire qui è che avevo un loop esterno e un loop interno in questo modo:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

  do some other stuff with x

Come puoi vedere, in realtà non andrà alla prossima x, ma andrà invece alla prossima y.

quello che ho scoperto per risolvere questo problema è stato semplicemente eseguire due volte l'array:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

for x in array:
  do some other stuff with x

So che questo è stato un caso specifico della domanda di OP, ma lo sto pubblicando nella speranza che possa aiutare qualcuno a pensare al proprio problema in modo diverso mantenendo le cose semplici.


Questo probabilmente non è Python. Qual è il tipo di array? Probabilmente elenco, ma cosa contiene? Anche se contiene ints, array.pop (x) probabilmente non farà ciò che desideri.
Veky,

È un buon punto. Non riesco a trovare il codice a cui ho fatto riferimento. Per chiunque legga questo, array.pop (i) "Rimuove l'elemento con l'indice i dall'array e lo restituisce." secondo la documentazione di Python. Quindi bisognerebbe ottenere l'indice dell'elemento x nell'array per far funzionare questo codice come previsto. C'è anche la funzione array.remove (x) che farebbe ciò che è previsto. Modificherò la mia risposta sopra per correggere quell'errore. Ciò presuppone che il secondo array non contenga duplicati, in quanto array.remove (x) rimuoverà solo la prima istanza di x found.
Nathan Garabedian,

Ok, allora ho capito. In quel caso, semplicemente usando breakinvece di continuefarebbe quello che vuoi, no? :-)
Veky,

Sì, per efficienza e chiarezza, probabilmente vorrai usare break invece di continuare in questi esempi. :)
Nathan Garabedian,

2

Prova a usare un generatore infinito.

from itertools import repeat
inputs = (get_input("Is this ok? (y/n)") for _ in repeat(None))
response = (i.lower()=="y" for i in inputs if i.lower() in ("y", "n"))

while True:
    #snip: print out current state
    if next(response):
        break
    #do more processing with menus and stuff

2

Utilizzando una funzione:

def myloop():
    for i in range(1,6,1):  # 1st loop
        print('i:',i)
        for j in range(1,11,2):  # 2nd loop
            print('   i, j:' ,i, j)
            for k in range(1,21,4):  # 3rd loop
                print('      i,j,k:', i,j,k)
                if i%3==0 and j%3==0 and k%3==0:
                    return  # getting out of all loops

myloop()

Prova a eseguire i codici sopra commentando anche returnquelli.

Senza usare alcuna funzione:

done = False
for i in range(1,6,1):  # 1st loop
    print('i:', i)
    for j in range(1,11,2):  # 2nd loop
        print('   i, j:' ,i, j)
        for k in range(1,21,4):  # 3rd loop
            print('      i,j,k:', i,j,k)
            if i%3==0 and j%3==0 and k%3==0:
                done = True
                break  # breaking from 3rd loop
        if done: break # breaking from 2nd loop
    if done: break     # breaking from 1st loop

Ora, esegui i codici sopra come prima e poi prova a eseguire commenti commentando ogni riga che contiene breakuno alla volta dal basso.


2

È possibile utilizzare un modo semplice per trasformare più loop in un singolo loop interrompibile numpy.ndindex

for i in range(n):
  for j in range(n):
    val = x[i, j]
    break # still inside the outer loop!

for i, j in np.ndindex(n, n):
  val = x[i, j]
  break # you left the only loop there was!

Devi indicizzare i tuoi oggetti, invece di essere in grado di iterare esplicitamente i valori, ma almeno in casi semplici sembra essere circa 2-20 volte più semplice della maggior parte delle risposte suggerite.


2
# this version uses a level counter to choose how far to break out

break_levels = 0
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_levels = 1        # how far nested, excluding this break
            break
        if ok == "n" or ok == "N":
            break                   # normal break
    if break_levels:
        break_levels -= 1
        break                       # pop another level
if break_levels:
    break_levels -= 1
    break

# ...and so on

1

probabilmente un piccolo trucco come sotto farà se non preferisce il refactorial in funzione

aggiunto 1 variabile break_level per controllare la condizione del ciclo while

break_level = 0
# while break_level < 3: # if we have another level of nested loop here
while break_level < 2:
    #snip: print out current state
    while break_level < 1:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": break_level = 2 # break 2 level
        if ok == "n" or ok == "N": break_level = 1 # break 1 level

1

È possibile definire una variabile (ad esempio break_statement ), quindi cambiarla in un valore diverso quando si verifica una condizione a due interruzioni e utilizzarla se l'istruzione si interrompe anche dal secondo ciclo.

while True:
    break_statement=0
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N": 
            break
        if ok == "y" or ok == "Y": 
            break_statement=1
            break
    if break_statement==1:
        break

Buon punto, tuttavia in ciascuno dei livelli al di sopra del nostro livello interiore di interesse avremmo bisogno di scansionare quella variabile. Sembra davvero male che la lingua non abbia un'istruzione GoTo, dal punto di vista delle prestazioni.
Anatoly Alekseev,

1

Vorrei ricordare che le funzioni in Python possono essere create proprio nel mezzo del codice e possono accedere in modo trasparente alle variabili circostanti per la lettura e con nonlocaloglobal dichiarazione per la scrittura.

Quindi puoi usare una funzione come "struttura di controllo fragile", definendo un posto in cui vuoi tornare:

def is_prime(number):

    foo = bar = number

    def return_here():
        nonlocal foo, bar
        init_bar = bar
        while foo > 0:
            bar = init_bar
            while bar >= foo:
                if foo*bar == number:
                    return
                bar -= 1
            foo -= 1

    return_here()

    if foo == 1:
        print(number, 'is prime')
    else:
        print(number, '=', bar, '*', foo)

>>> is_prime(67)
67 is prime
>>> is_prime(117)
117 = 13 * 9
>>> is_prime(16)
16 = 4 * 4

1

Soluzioni in 2 modi

Con un esempio: queste due matrici sono uguali / uguali?
matrix1 e matrix2 hanno le stesse dimensioni, n, 2 matrici dimensionali.

Prima soluzione , senza una funzione

same_matrices = True
inner_loop_broken_once = False
n = len(matrix1)

for i in range(n):
    for j in range(n):

        if matrix1[i][j] != matrix2[i][j]:
            same_matrices = False
            inner_loop_broken_once = True
            break

    if inner_loop_broken_once:
        break

Seconda soluzione , con una funzione
Questa è la soluzione finale per il mio caso

def are_two_matrices_the_same (matrix1, matrix2):
    n = len(matrix1)
    for i in range(n):
        for j in range(n):
            if matrix1[i][j] != matrix2[i][j]:
                return False
    return True

Buona giornata!


1
# this version breaks up to a certain label

break_label = None
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_label = "outer"   # specify label to break to
            break
        if ok == "n" or ok == "N":
            break
    if break_label:
        if break_label != "inner":
            break                   # propagate up
        break_label = None          # we have arrived!
if break_label:
    if break_label != "outer":
        break                       # propagate up
    break_label = None              # we have arrived!

#do more processing with menus and stuff

0

Speriamo che questo aiuti:

x = True
y = True
while x == True:
    while y == True:
         ok = get_input("Is this ok? (y/n)") 
         if ok == "y" or ok == "Y":
             x,y = False,False #breaks from both loops
         if ok == "n" or ok == "N": 
             break #breaks from just one

0

Ecco un'implementazione che sembra funzionare:

break_ = False
for i in range(10):
    if break_:
        break
    for j in range(10):
        if j == 3:
            break_ = True
            break
        else:
            print(i, j)

L'unico inconveniente è che devi definire break_prima dei loop.


0

Non è possibile farlo a livello linguistico. Alcune lingue hanno un goto altri hanno una pausa che accetta un argomento, Python no.

Le migliori opzioni sono:

  1. Imposta un flag che viene controllato dal loop esterno o imposta la condizione dei loop esterni.

  2. Metti il ​​loop in una funzione e usa return per uscire da tutti i loop contemporaneamente.

  3. Riformula la tua logica.

Il merito va a Vivek Nagarajan, programmatore dal 1987


Utilizzando la funzione

def doMywork(data):
    for i in data:
       for e in i:
         return 

Usando la bandiera

is_break = False
for i in data:
   if is_break:
      break # outer loop break
   for e in i:
      is_break = True
      break # inner loop break

-3

Simile a quello precedente, ma più compatto. (I booleani sono solo numeri)

breaker = False #our mighty loop exiter!
while True:
    while True:
        ok = get_input("Is this ok? (y/n)")
        breaker+= (ok.lower() == "y")
        break

    if breaker: # the interesting part!
        break   # <--- !

2
Questo sembra piuttosto brutto e rende il codice più difficile da capire, rispetto al precedente. Inoltre, è sbagliato. Manca di verificare se l'ingresso è accettabile e si interrompe dopo 1 loop.
Eric,

-3

Dal momento che questa domanda è diventata una domanda standard per entrare in un particolare ciclo, vorrei dare la mia risposta usando l'esempio Exception.

Sebbene non esista un'etichetta denominata interruzione del ciclo nel costrutto a più cicli, possiamo fare uso delle eccezioni definite dall'utente per interrompere un particolare ciclo di nostra scelta. Considera l'esempio seguente in cui stampiamo tutti i numeri fino a 4 cifre nel sistema di numerazione base-6:

class BreakLoop(Exception):
    def __init__(self, counter):
        Exception.__init__(self, 'Exception 1')
        self.counter = counter

for counter1 in range(6):   # Make it 1000
    try:
        thousand = counter1 * 1000
        for counter2 in range(6):  # Make it 100
            try:
                hundred = counter2 * 100
                for counter3 in range(6): # Make it 10
                    try:
                        ten = counter3 * 10
                        for counter4 in range(6):
                            try:
                                unit = counter4
                                value = thousand + hundred + ten + unit
                                if unit == 4 :
                                    raise BreakLoop(4) # Don't break from loop
                                if ten == 30: 
                                    raise BreakLoop(3) # Break into loop 3
                                if hundred == 500:
                                    raise BreakLoop(2) # Break into loop 2
                                if thousand == 2000:
                                    raise BreakLoop(1) # Break into loop 1

                                print('{:04d}'.format(value))
                            except BreakLoop as bl:
                                if bl.counter != 4:
                                    raise bl
                    except BreakLoop as bl:
                        if bl.counter != 3:
                            raise bl
            except BreakLoop as bl:
                if bl.counter != 2:
                    raise bl
    except BreakLoop as bl:
        pass

Quando stampiamo l'output, non otterremo mai alcun valore il cui posto dell'unità è con 4. In quel caso, non ci rompiamo da nessun loop poiché BreakLoop(4)viene sollevato e catturato nello stesso loop. Allo stesso modo, ogni volta che dieci posti hanno 3, entriamo nel terzo ciclo usando BreakLoop(3). Ogni volta che centinaia di posti hanno 5, ci dividiamo nel secondo ciclo usando BreakLoop(2)e ogni volta che i mille posti hanno 2, ci dividiamo nel primo ciclo usandoBreakLoop(1) .

In breve, aumenta la tua eccezione (incorporata o definita dall'utente) nei loop interni e prendila nel loop da cui desideri riprendere il controllo. Se si desidera interrompere da tutti i loop, catturare l'eccezione al di fuori di tutti i loop. (Non ho mostrato questo caso nell'esempio).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.