Como sair de vários loops?


481

Dado o seguinte código (que não funciona):

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

Existe uma maneira de fazer isso funcionar? Ou devo fazer uma verificação para interromper o loop de entrada e, em seguida, outra verificação mais limitada no loop externo para interromper todos juntos, se o usuário estiver satisfeito?


87
Por que o Python não possui apenas 'break (n)' onde n é o número de níveis dos quais você deseja sair.
Nathan

2
O C ++ é legal aqui, gotose você estiver aninhado em muitos loops #
Drake Johnson

Respostas:


512

Meu primeiro instinto seria refatorar o loop aninhado em uma função e usá-lo returnpara sair.


3
Este é outro pensamento que eu tive, já que uma função get_input_yn () também seria útil em outros lugares, tenho certeza.
Matthew Scharley 10/10/08

96
concordou nesse caso específico, mas no caso geral de 'eu aninhei loops, o que eu faço' a refatoração pode não fazer sentido.
10138 quick_dry

o uso de uma exceção pode ser mais fácil quando você deve produzir em vez de retornar, no entanto, provavelmente você deve usar itertools.islice () nesse caso.
robert king

5
Geralmente é possível refatorar o loop interno em seu próprio método, que retorna true para continuar, false para quebrar o loop externo. enquanto condition1: / se não MyLoop2 (params): break. Uma alternativa é definir um sinalizador booleano, que é testado nos dois níveis. mais = True / while condition1 e mais: / while condition2 e mais: / se stopCondition: mais = / break Falso / ...
ToolmakerSteve

7
Concordo que se esforçar para usar returné a abordagem correta. E o raciocínio é que, de acordo com o Zen de Python , "flat é melhor que aninhado". Temos três níveis de aninhamento aqui e, se isso começar a atrapalhar, é hora de reduzir o aninhamento ou, pelo menos, extrair todo o aninhamento para uma função própria.
Lutz Prechelt

240

Aqui está outra abordagem que é curta. A desvantagem é que você só pode quebrar o loop externo, mas às vezes é exatamente o que você deseja.

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

Isso usa a construção for / else explicada em: Por que o python usa 'else' depois dos loops for e while?

Informações principais: parece que o loop externo sempre quebra. Mas se o loop interno não quebrar, o loop externo também não.

A continueafirmação é a mágica aqui. Está na cláusula for-else. Por definição, isso acontece se não houver interrupção interna. Nessa situação, continueevita-se a ruptura externa.


6
@eugeney Por que não? A primeira interrupção sairá do loop interno.
Navin

5
@eugeney Sinto que estou perdendo alguma coisa aqui. Você pode postar um exemplo?
Navin

4
@Mingliang que pode ir antes da continuação.
precisa

1
Entendi isso em um vídeo de Raymond Hettinger, youtu.be/OSGv2VnC0go?t=971 , leia as instruções "else" anexadas aos loops como "no_break", então fica mais fácil entender.
Ambareesh

2
Isso é inteligente. :-) No entanto, não é direto. Francamente, não estou convencido por argumentos de manter rotulado break ou break (n) fora do Python. As soluções alternativas adicionam mais complexidade.
rfportilla

148

O PEP 3136 propõe quebras / continue rotuladas. Guido o rejeitou porque "código tão complicado para exigir esse recurso é muito raro". O PEP menciona algumas soluções alternativas (como a técnica de exceção), enquanto Guido considera que a refatoração para usar o retorno será mais simples na maioria dos casos.


73
Embora refatorar / returngeralmente seja o caminho a percorrer, já vi alguns casos em que uma simples break 2declaração concisa ' ' faria tanto sentido. Além disso, refatorar / returnnão funciona da mesma maneira continue. Nesses casos, a quebra numérica e a continuação seriam mais fáceis de seguir e menos confusas do que refatorar para uma função minúscula, gerar exceções ou lógica complicada envolvendo a configuração de um sinalizador para quebrar em cada nível de ninho. É uma pena que Guido tenha rejeitado.
James Haigh

10
break; breakseria bom.
21413 PyRulez

5
@Jeyekomon O problema é que você não precisa de 3 ou mais loops aninhados para que isso seja um problema. 2 loops aninhados são bastante comuns
Jon

6
"Código tão complicado para exigir esse recurso é muito raro". Mas se você usar um código tão complicado, a falta de loops rotulados o tornará ainda mais complicado, pois você deverá encaminhar manualmente breaktodos os loops. Estúpido.
precisa

3
Aparentemente, só posso editar uma postagem por 5 minutos (faz 6). Então, aqui está o meu post editado: Meus 2 centavos: Perl rotulou break (mas chama de 'last') e 'next' para prosseguir diretamente para a próxima iteração. Não é nada raro - eu uso o tempo todo. Sou novato no Python e já preciso disso. Além disso, as quebras numeradas seriam horríveis para refatoração - é melhor rotular o loop que você deseja interromper e, em seguida, use break <label> para declarar explicitamente qual loop você deseja interromper.
John Deighan

119

Primeiro, a lógica comum é útil.

Se, por algum motivo, as condições de encerramento não puderem ser resolvidas, as exceções são um plano de retorno.

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

Para este exemplo específico, uma exceção pode não ser necessária.

Por outro lado, geralmente temos as opções "Y", "N" e "Q" nos aplicativos de modo caractere. Para a opção "Q", queremos uma saída imediata. Isso é mais excepcional.


4
Sério, as exceções são extremamente baratas e o python idiomático usa muitos e muitos deles. É muito fácil definir e lançar os personalizados também.
Gregg Lind

13
Idéia interessante. Estou dividido quanto a amar ou odiar.
Craig McQueen

8
Essa solução seria mais útil se mostrasse as duas variações separadamente. (1) usando uma bandeira ( done). (2) levantando uma exceção. Mesclá-los em uma única solução apenas faz com que pareça complicado. Para futuros leitores: UTILIZE todas as linhas que envolvem doneOU definem GetOutOfLoop(Exception)e aumentam / exceto isso.
Home

4
Em geral, o uso de try-blocks para outras coisas que não exceções é muito desaprovado. Try-blocks são projetados especificamente para tratamento de erros, e usá-los para algum fluxo de controle estranho não é muito bom, estilisticamente.
nobillygreen

3
@ tommy.carstensen Isso é um absurdo; definir uma nova subclasse de exceção e aumentá-la (como mostrado na resposta) e passar uma mensagem personalizada para o Exceptionconstrutor (por exemplo raise Exception('bla bla bla')) são válidas no Python 2 e no Python 3. O primeiro é preferível nesse caso, porque não queremos nosso exceptbloco para capturar todas as exceções, mas apenas a exceção especial que estamos usando para sair do loop. Se fizermos as coisas da maneira que você sugere e, em seguida, um bug em nosso código fizer com que uma exceção inesperada seja levantada, ela será tratada incorretamente da mesma forma que sair deliberadamente do loop.
Mark Amery

54

Costumo concordar que a refatoração em uma função geralmente é a melhor abordagem para esse tipo de situação, mas para quando você realmente precisa interromper os loops aninhados, aqui está uma variante interessante da abordagem de geração de exceção descrita pela @ S.Lott. Ele usa a withdeclaração do Python para tornar a criação de exceção um pouco melhor. Defina um novo gerenciador de contexto (você só precisa fazer isso uma vez) com:

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

Agora você pode usar este gerenciador de contexto da seguinte maneira:

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"

Vantagens: (1) é um pouco mais limpo (sem tentativa explícita, exceto bloco) e (2) você obtém uma Exceptionsubclasse personalizada para cada uso de nested_break; não é necessário declarar sua própria Exceptionsubclasse a cada vez.


40

Primeiro, você também pode considerar tornar o processo de obtenção e validação da entrada uma função; dentro dessa função, você pode simplesmente retornar o valor se o seu correto, e mantê-fiação no enquanto loop se não. Isso evita essencialmente o problema que você resolveu e geralmente pode ser aplicado no caso mais geral (quebra de vários loops). Se você absolutamente deve manter essa estrutura em seu código e realmente não deseja lidar com os booleanos da contabilidade ...

Você também pode usar goto da seguinte maneira (usando um módulo April Fools daqui ):

#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

Eu sei, eu sei, "você não usará goto" e tudo mais, mas funciona bem em casos estranhos como este.


1
Se for algo parecido com o comando COME FROM em INTERCAL, então nada
1800 INFORMAÇÃO

3
Eu gosto da brincadeira, mas o ponto de estouro de pilha é promover um bom código, então eu tenho que votar para baixo :(
Christian Oudard

13
Eu acho que é uma solução limpa e legível o suficiente para se qualificar como um bom código, então eu voto nele. :)
JT Hurley

1
@ JTHurley não, isso não é limpo e legível. Quero dizer, pode parecer limpo e legível neste exemplo, mas em qualquer cenário da vida real é preciso criar uma bagunça sagrada . (Além disso, este é tão anti-pythônico ...)
Alois Mahdal

2
goto recebe uma má reputação, qualquer codificador profissional deve ser capaz de lidar com isso corretamente na minha opinião.
Albert Renshaw

33

Introduzir uma nova variável que você usará como um 'disjuntor'. Primeiro atribua algo a ele (Falso, 0, etc.) e, em seguida, dentro do loop externo, antes de sair dele, altere o valor para outra coisa (True, 1, ...). Depois que o loop sair, faça o loop 'pai' verificar esse valor. Deixe-me demonstrar:

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 você tem um loop infinito, esta é a única saída; para outros loops, a execução é realmente muito mais rápida. Isso também funciona se você tiver muitos loops aninhados. Você pode sair de todos, ou apenas alguns. Infinitas possibilidades! Espero que isso tenha ajudado!


22

Para interromper vários loops aninhados, sem refatorar em uma função, use uma "instrução goto simulada" com a exceção StopIteration interna :

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

except StopIteration: pass

Consulte esta discussão sobre o uso de instruções goto para interromper loops aninhados.


1
Isso parece muito melhor do que criar sua própria classe para lidar com a exceção e parece muito limpo. Existe alguma razão para eu não fazer isso?
mgjk 16/09/19

De fato, o StopIteration está sendo usado para geradores, mas acho que normalmente você não tem nenhuma exceção StopIteration não corrigida. Portanto, parece uma boa solução, mas não há nenhum erro em criar uma nova exceção.
Kowalski

1
Melhor e mais simples solução para mim
Alexandre Huat 21/02

16

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

ou algo assim. Você pode definir uma variável no loop interno e verificá-la no loop externo imediatamente após a saída do loop interno, quebrando, se apropriado. Eu meio que gosto do método GOTO, desde que você não se importe em usar o módulo de piadas do April Fool - não é Pythonic, mas faz sentido.


isso é uma espécie de configuração de sinalizador!
SIslam

Eu acho que é uma solução muito boa.
Kowalski

13

Esta não é a maneira mais bonita de fazer isso, mas na minha opinião, é a melhor maneira.

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

Tenho certeza de que você poderia descobrir algo usando recursão aqui também, mas não sei se essa é uma boa opção para você.


Esta foi a solução certa para mim. Meu caso de uso era muito diferente dos OP. Eu estava repetindo essencialmente os mesmos dados duas vezes para encontrar permutações, então não queria separar os dois enquanto os loops.
Brian Peterson

9

E por que não continuar repetindo se duas condições são verdadeiras? Eu acho que essa é uma maneira mais pitônica:

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

Não é?

Muito bem sucedida.


por que não apenas while dejaVu:? Você define como verdadeiro de qualquer maneira.
Matthew Scharley

ei, isso funciona! Eu estava pensando em duas Truecondições para pular dois loops, mas apenas um é suficiente.
Mauro Aspé

2
@ MatthewScharley Acho que isso mostra que isso funciona em loops aninhados.
manipula

@ MauroAspé, isso não fará exatamente o que o OP solicita. ele ainda irá executar o loop externo inteiro, mas a meta é que se você quebrar o resto do código não serão executados
yamm

@yamm Não foi possível resolver isso com um if not dejaVu: breakna parte inferior e, assim, sair do loop principal? Eu acho que a solução está mais próxima do que foi solicitado. +1
milcak

8

Fatore sua lógica de loop em um iterador que produz as variáveis ​​de loop e retorna quando concluído - aqui está uma simples que expõe imagens em linhas / colunas até ficarmos sem imagens ou fora de locais para colocá-las:

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 ...

Isso tem a vantagem de dividir a lógica complicada do loop e o processamento ...


3

Nesse caso, como apontado por outros, a decomposição funcional é o caminho a percorrer. Código em 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

Existe um truque oculto na while ... elseestrutura do Python que pode ser usado para simular a quebra dupla sem muitas alterações / adições de código. Em essência, se a whilecondição for falsa, o elsebloco é acionado. Nenhuma exceção continueou breakacionar o elsebloco. Para obter mais informações, consulte as respostas à " Cláusula Else no Python while statement " ou no documento Python 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

A única desvantagem é que você precisa mover a condição de quebra dupla para a whilecondição (ou adicionar uma variável de flag). Variações disso também existem para o forloop, onde o elsebloco é acionado após a conclusão do loop.


Isso parece não cumprir o requisito de pausas duplas. Funciona para o problema exato, mas não para a pergunta real.
Dakkaron 5/10

@Dakkaron Tem certeza de que entendeu o código corretamente? O código realmente resolve a questão dos OPs e quebra de maneira semelhante à solicitação. No entanto, ele não interrompe vários loops, mas usa a cláusula else para substituir a necessidade de duplicar o intervalo.
holroy

Pelo meu entendimento, a pergunta era How to break out of multiple loops in Python?e a resposta deveria ter sido "Não funciona, tente outra coisa". Eu sei que isso corrige o exemplo exato do OP, mas não responde à pergunta deles.
Dakkaron

@ Dakarkar, veja a declaração do problema sob o código e, na minha opinião, ela realmente responde à pergunta dos OPs.
holroy

2

Outra maneira de reduzir sua iteração para um loop de nível único seria através do uso de geradores, como também especificado na referência python

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

Você pode escalá-lo para qualquer número de níveis para o loop

A desvantagem é que você não pode mais quebrar apenas um único nível. É tudo ou nada.

Outra desvantagem é que ele não funciona com um loop while. Originalmente, eu queria postar esta resposta no Python - `break` fora de todos os loops, mas infelizmente isso está fechado como uma duplicata deste


1
Funciona também enquanto loops, você só precisa escrever seu gerador como um def (com rendimento), não como uma compreensão.
Veky

Sim, um orador de uma PyCon afirma aqui que mesmo a resposta aceita por RobertRossney não é verdadeiramente Pythonic, mas um gerador é o caminho certo para quebrar vários loops. (Eu recomendo assistir o vídeo inteiro!) #
21919 Post189

2

Minha razão para vir aqui é que eu tinha um loop externo e um loop interno da seguinte forma:

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

Como você pode ver, ele não vai realmente para o próximo x, mas para o próximo y.

o que eu encontrei para resolver isso era simplesmente executar o array duas vezes:

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

Sei que esse foi um caso específico da pergunta do OP, mas estou postando na esperança de que ajude alguém a pensar sobre seu problema de maneira diferente, mantendo as coisas simples.


Provavelmente não é Python. Qual é o tipo de matriz? Provavelmente lista, mas o que contém? Mesmo que contenha ints, o array.pop (x) provavelmente não fará o que você deseja.
Veky

Este é um bom ponto. Não consigo encontrar o código que referenciei. Para quem estiver lendo isso, array.pop (i) "Remove o item com o índice i da matriz e o retorna." conforme documentação do python. Portanto, seria necessário obter o índice do item x na matriz para fazer esse código funcionar conforme o esperado. Há também a função array.remove (x) que faria o que é esperado. Modificarei minha resposta acima para corrigir esse erro. Isso pressupõe que a segunda matriz não contém duplicatas, pois array.remove (x) removerá apenas a primeira instância de x encontrada.
19719 Nathan Garabedian

Ok, entendi. Nesse caso, simplesmente usar em breakvez de continuefaria o que você deseja, não faria? :-)
Veky

Sim, para maior eficiência e clareza, você provavelmente desejaria usar break em vez de continuar nesses exemplos. :)
Nathan Garabedian

2

Tente usar um gerador 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

Usando uma função:

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

Tente executar os códigos acima comentando returntambém.

Sem usar nenhuma função:

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

Agora, execute os códigos acima, como é o primeiro, e tente executar comentando cada linha que contém breakuma de cada vez na parte inferior.


2

Uma maneira fácil de transformar vários loops em um único loop quebrável é usar 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!

Você precisa indexar seus objetos, em vez de poder iterar os valores explicitamente, mas pelo menos em casos simples, parece ser aproximadamente 2-20 vezes mais simples do que a maioria das respostas sugeridas.


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

provavelmente um pequeno truque como abaixo fará se não preferir refatorar a função

adicionada 1 variável break_level para controlar a condição do loop 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

Você pode definir uma variável (por exemplo, break_statement ) e alterá-la para um valor diferente quando ocorrer uma condição de duas interrupções e usá-la na instrução if para interromper também o segundo loop.

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

Bom ponto, no entanto, em cada um dos níveis acima do nosso nível de interesse interno, precisaríamos examinar essa variável. É realmente ruim que o idioma não tenha uma instrução GoTo, em termos de desempenho.
Anatoly Alekseev

1

Gostaria de lembrá-lo que as funções no Python podem ser criadas bem no meio do código e podem acessar as variáveis ​​circundantes de forma transparente para leitura e com nonlocalouglobal declaração para escrita.

Portanto, você pode usar uma função como uma "estrutura de controle quebrável", definindo um local para o qual deseja retornar:

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

Soluções de 2 maneiras

Com um exemplo: essas duas matrizes são iguais / iguais?
matrix1 e matrix2 são do mesmo tamanho, n, 2 matrizes dimensionais.

Primeira solução , sem função

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

Segunda solução , com uma função
Esta é a solução final para o meu 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

Tenha um bom dia!


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

Espero que isso ajude:

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

Aqui está uma implementação que parece funcionar:

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)

A única desvantagem é que você deve definir break_antes dos loops.


0

Não há como fazer isso no nível do idioma. Algumas linguagens têm um goto, outras têm uma pausa que exige um argumento, o python não.

As melhores opções são:

  1. Defina um sinalizador que é verificado pelo loop externo ou defina a condição de loops externos.

  2. Coloque o loop em uma função e use return para interromper todos os loops de uma só vez.

  3. Reformule sua lógica.

O crédito vai para Vivek Nagarajan, programador desde 1987


Usando a Função

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

Usando sinalizador

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

Semelhante como o anterior, mas mais compacto. (Booleanos são apenas números)

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
Isso parece muito feio e torna o código mais difícil de entender, em comparação com o anterior. Além disso, está errado. Ele deixa de verificar se a entrada é aceitável e quebra após 1 loop.
Eric

-3

Como essa pergunta se tornou uma pergunta padrão para quebrar um loop específico, eu gostaria de dar minha resposta com o exemplo usando Exception.

Embora não exista um rótulo chamado quebra de loop na construção de loop multipolar, podemos usar exceções definidas pelo usuário para entrar em um loop específico de nossa escolha. Considere o exemplo a seguir, onde vamos imprimir todos os números de até 4 dígitos no sistema de numeração da 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 imprimimos a saída, nunca obteremos nenhum valor cujo local da unidade seja com 4. Nesse caso, não quebramos nenhum loop, pois ele BreakLoop(4)é gerado e capturado no mesmo loop. Da mesma forma, sempre que dez lugares tiverem 3, entraremos no terceiro loop usando BreakLoop(3). Sempre que cem lugares estão com 5, entramos no segundo loop usando BreakLoop(2)e sempre que o milésimo lugar está tendo 2, entramos no primeiro loop usandoBreakLoop(1) .

Em resumo, aumente sua Exceção (embutida ou definida pelo usuário) nos loops internos e pegue-a no loop de onde você deseja retomar o controle. Se você deseja interromper todos os loops, pegue a exceção fora de todos os loops. (Eu não mostrei este caso no exemplo).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.