Как вырваться из нескольких петель?


482

Учитывая следующий код (это не работает):

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

Есть ли способ сделать эту работу? Или я должен сделать одну проверку, чтобы выйти из цикла ввода, а затем другую, более ограниченную, проверить во внешнем цикле, чтобы разорвать все вместе, если пользователь удовлетворен?


87
Почему в Python просто нет 'break (n)', где n - это количество уровней, из которых вы хотите выйти.
Натан

2
С ++ здесь хорош, gotoесли вы глубоко
Дрейк Джонсон

Ответы:


512

Моим первым инстинктом было бы реорганизовать вложенный цикл в функцию и использовать ее returnдля разрыва.


3
Это еще одна мысль, которая у меня возникла, поскольку функция get_input_yn () была бы полезна и в других местах, я уверен.
Мэтью Шарли

96
в этом конкретном случае согласились, но в общем случае «у меня есть вложенные циклы, что мне делать» рефакторинг может не иметь смысла.
quick_dry

Использование исключения может быть проще, когда вы должны выполнить yield вместо использования return, однако, вероятно, вам следует использовать itertools.islice () в таком случае.
Роберт

5
Обычно возможно реорганизовать внутренний цикл в его собственный метод, который возвращает true для продолжения, false для разрыва внешнего цикла. в то время как условие 1: / если не MyLoop2 (params): перерыв. Альтернативой является установка логического флага, который тестируется на обоих уровнях. more = True / while condition1 и более: / while condition2 и более: / if stopCondition: more = False / break / ...
ToolmakerSteve

7
Я согласен, что стремление использовать returnэто правильный подход. И причина в том, что, согласно дзену Python , «квартира лучше вложенной». Здесь у нас есть три уровня вложенности, и если это начинает мешать, пришло время уменьшить вложенность или, по крайней мере, извлечь целое вложение в свою собственную функцию.
Лутц Пречелт

240

Вот еще один короткий подход. Недостатком является то, что вы можете разорвать только внешний цикл, но иногда это именно то, что вы хотите.

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

Здесь используется конструкция for / else, объясненная в: Почему Python использует «else» после циклов for и while?

Основная идея: только кажется, что внешний цикл всегда прерывается. Но если внутренний цикл не прерывается, внешний цикл тоже не будет.

continueЗаявление магия здесь. Это в пункте для другого. По определению это происходит, если нет внутреннего разрыва. В этой ситуации continueаккуратно обходит внешний разрыв.


6
@eugeney Почему бы и нет? Первый разрыв выйдет из внутреннего цикла.
Навин

5
@eugeney Я чувствую, что здесь чего-то не хватает. Вы можете опубликовать пример?
Навин

4
@Mingliang, который может идти до продолжения.
Baldrickk

1
Получил это из видео Рэймонда Хеттингера, youtu.be/OSGv2VnC0go?t=971 , прочитал операторы «else», прикрепленные к циклам for как «no_break», тогда это станет легче для понимания.
Амбариш

2
Это умно. :-) Впрочем, не прямолинейно. Честно говоря, меня не убеждают аргументы, чтобы держать помеченный как break или break (n) вне Python. Обходные пути добавляют больше сложности.
rfportilla

148

PEP 3136 предлагает помеченный перерыв / продолжение. Гвидо отверг это, потому что «код, настолько сложный, чтобы требовать эту функцию, очень редок». Однако в PEP упоминаются некоторые обходные пути (например, метод исключения), в то время как Гвидо считает, что рефакторинг для использования return будет проще в большинстве случаев.


73
Несмотря на то, что рефакторинг / return- это, как правило, путь, я видел довольно много случаев, когда простое сжатое break 2утверждение ' ' имело бы столько смысла. Кроме того, рефакторинг / returnне работает так же для continue. В этих случаях будет проще следовать числовому разбиению и продолжению, и оно будет менее загромождено, чем рефакторинг крошечной функции, вызывая исключения или замысловатую логику, включающую установку флага для разбиения на каждом уровне гнезда. Обидно, Гвидо это отверг.
Джеймс Хей

10
break; breakбыло бы здорово.
PyRulez

5
@Jeyekomon Проблема в том, что вам не нужно 3 или более вложенных циклов, чтобы это было проблемой. 2 вложенных цикла довольно распространены
Jon

6
«Код, настолько сложный, чтобы требовать эту функцию, очень редок». Но если вы когда-нибудь будете использовать такой сложный код, отсутствие помеченных циклов сделает его еще более сложным, так как вы должны вручную перебрать breakвсе циклы. Глупый.
BallpointBen

3
Видимо, я могу редактировать пост только за 5 минут (прошло уже 6). Итак, вот мой отредактированный пост: Мои 2 цента: Perl пометил break (но называет это 'last') и 'next', чтобы перейти непосредственно к следующей итерации. Это не редкость - я использую это все время. Я новичок в Python и уже нуждаюсь в этом. Кроме того, пронумерованные разрывы были бы ужасны для рефакторинга - лучше пометить цикл, из которого вы хотите разорвать, а затем использовать break <label>, чтобы явно указать, из какого цикла вы хотите разорвать.
Джон Дейган

119

Во-первых, обычная логика полезна.

Если по какой-либо причине условия прекращения не могут быть разработаны, исключения являются запасным планом.

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

Для этого конкретного примера исключение может не потребоваться.

С другой стороны, у нас часто есть опции «Y», «N» и «Q» в символьных приложениях. Для опции «Q» мы хотим немедленный выход. Это более исключительно.


4
Серьезно, исключения чрезвычайно дешевы, и идиоматический питон использует их очень много. Также очень легко определять и создавать собственные.
Грегг Линд

13
Интересная идея. Я разрываюсь относительно того, любить это или ненавидеть это.
Крейг МакКуин

8
Это решение было бы более полезным, если бы оно показывало две вариации отдельно. (1) использование флага ( done). (2) поднятие исключения. Объединение их в одно решение просто делает его сложным. Для будущих читателей: ЛИБО используйте все участвующие строки done, ИЛИ определяйте GetOutOfLoop(Exception)и повышайте / кроме этого.
ToolmakerSteve

4
В общем, использование блоков try для чего-то другого, кроме исключений, весьма неодобрительно. Try-блоки специально разработаны для обработки ошибок, и использование их для некоторого странного потока управления не очень хорошо, стилистически.
nobillygreen

3
@ tommy.carstensen Это чепуха; и определение нового подкласса исключения и его поднятие (как показано в ответе) и передача пользовательского сообщения Exceptionконструктору (например raise Exception('bla bla bla')) допустимы как в Python 2, так и в Python 3. Первое предпочтительнее в этом случае, потому что мы не хотим наш exceptблок для перехвата всех исключений, но только специального исключения, которое мы используем для выхода из цикла. Если мы будем действовать так, как вы предлагаете, а затем ошибка в нашем коде вызовет непредвиденное исключение, то это будет ошибочно восприниматься так же, как преднамеренный выход из цикла.
Марк Амери

54

Я склонен согласиться с тем, что рефакторинг в функцию обычно является наилучшим подходом для такого рода ситуаций, но для случаев, когда вам действительно нужно вырваться из вложенных циклов, вот интересный вариант подхода, вызывающего исключения, который описал @ S.Lott. Он использует withоператор Python, чтобы повышение исключений выглядело немного лучше. Определите новый менеджер контекста (вы должны сделать это только один раз) с:

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

Теперь вы можете использовать этот менеджер контекста следующим образом:

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"

Преимущества: (1) он немного чище (без явного блока try-кроме), и (2) вы получаете пользовательский Exceptionподкласс для каждого использования nested_break; нет необходимости Exceptionкаждый раз объявлять свой собственный подкласс.


40

Во-первых, вы также можете подумать о том, чтобы сделать процесс получения и проверки входных данных функцией; в рамках этой функции, вы можете просто вернуть значение , если его правильно, и держать спиннинг в то время как петли , если нет. По сути, это устраняет проблему, которую вы решили, и обычно может применяться в более общем случае (разрыв нескольких циклов). Если вам абсолютно необходимо сохранить эту структуру в своем коде, и вы действительно не хотите иметь дело с булевыми значениями бухгалтерии ...

Вы также можете использовать goto следующим образом (используя модуль April Fools отсюда ):

#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

Я знаю, я знаю, «ты не должен использовать goto» и все такое, но это хорошо работает в странных случаях, подобных этому.


1
Если это что-то наподобие команды COME FROM в INTERCAL, то ничего
1800 ИНФОРМАЦИЯ

3
Мне нравится шутка, но смысл переполнения стека в том, чтобы продвигать хороший код, поэтому я должен проголосовать за вас :(
Кристиан Оудард

13
Я думаю, что это чистое и достаточно читабельное решение, которое можно квалифицировать как хороший код, поэтому я голосую за него. :)
JT Hurley

1
@JTHurley нет, это не чисто и читабельно. Я имею в виду, что в этом примере это может показаться чистым и читабельным, но в любом сценарии реальной жизни Гото создает священный беспорядок . (Также это ооочень антипифонический ...)
Алоис Махдал

2
Goto получает плохую репутацию, по моему мнению, любой профессиональный программист должен быть в состоянии справиться с этим должным образом.
Альберт Реншоу

33

Введите новую переменную, которую вы будете использовать как «прерыватель цикла». Сначала присвойте ему что-нибудь (False, 0 и т. Д.), А затем, во внешнем цикле, перед тем как выйти из него, измените значение на что-то другое (True, 1, ...). Как только цикл выйдет, сделайте родительский цикл для проверки этого значения. Позвольте мне продемонстрировать:

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

Если у вас бесконечный цикл, это единственный выход; для других циклов выполнение действительно намного быстрее. Это также работает, если у вас много вложенных циклов. Вы можете выйти из всех, или только несколько. Безграничные возможности! Надеюсь, это помогло!


22

Чтобы разорвать несколько вложенных циклов без рефакторинга в функцию, используйте «симулированный оператор goto» со встроенным исключением StopItered :

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

except StopIteration: pass

Посмотрите это обсуждение использования операторов goto для разрыва вложенных циклов.


1
Это выглядит намного лучше, чем создание собственного класса для обработки исключения, и выглядит очень чисто. Есть ли причина, по которой я не должен этого делать?
mgjk

На самом деле StopIteration используется для генераторов, но я думаю, что обычно у вас нет никаких исключений StopItered. Таким образом, это кажется хорошим решением, но в любом случае нет ошибки при создании нового исключения.
Ковальский

1
Самое лучшее и простое решение для меня
Александр Хуат

16

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

или что-то типа того. Вы можете установить переменную во внутреннем цикле и проверить ее во внешнем цикле сразу после выхода из внутреннего цикла, прервав при необходимости. Мне нравится метод GOTO, при условии, что вы не возражаете против использования модуля первоапрельской шутки - он не Pythonic, но он имеет смысл.


это своего рода установка флага!
SIslam

Я думаю, что это очень хорошее решение.
Ковальский

13

Это не самый красивый способ сделать это, но, на мой взгляд, это лучший способ.

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

Я почти уверен, что и здесь вы можете что-то придумать, используя рекурсию, но я не знаю, подходит ли вам этот вариант.


Это было правильное решение для меня. Мой вариант использования сильно отличался от ОП. Я дважды просматривал по существу одни и те же данные, чтобы найти перестановки, поэтому я не хотел разделять два цикла while.
Брайан Петерсон

9

И почему бы не продолжать цикл, если выполняются два условия? Я думаю, что это более питонический способ:

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

Не так ли?

Всего наилучшего.


почему не просто while dejaVu:? В любом случае вы устанавливаете его в true.
Мэтью Шарли

эй, это работает! Я думал в двух Trueусловиях пропустить две петли, но одной достаточно.
Мауро Аспе

2
@ MatthewScharley Я думаю, это должно показать, что это работает во вложенных циклах.
обрабатывать

@ MauroAspé это не будет делать то, что запрашивает OP. он по-прежнему будет выполнять весь внешний цикл, но цель состоит в том, что, если вы
прервете,

@yamm Может ли это быть решено с помощью if not dejaVu: breakвнизу и, таким образом, выйти из основного цикла? Я думаю, что решение наиболее близко к тому, что было задано. +1
milcak

8

Разложите логику вашего цикла в итератор, который возвращает переменные цикла и возвращает, когда все готово - вот простое, которое выкладывает изображения в строки / столбцы до тех пор, пока у нас не будет изображений или нет мест для их размещения:

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

Это имеет преимущество разделения сложной логики цикла и обработки ...


3

В этом случае, как отмечают и другие, функциональная декомпозиция - это путь. Код в 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

В while ... elseструктуре Python есть скрытый трюк, который можно использовать для имитации двойного разрыва без особых изменений / дополнений кода. По сути, если whileусловие ложно, elseблок срабатывает. Ни исключений, continueни breakтриггера elseблока. Для получения дополнительной информации см. Ответы на « Предложение Else для Python while Statement » или документацию 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

Единственным недостатком является то, что вам нужно переместить условие двойного разбиения в whileусловие (или добавить переменную flag). Вариации этого существуют и для forцикла, где elseблок запускается после завершения цикла.


Это не соответствует требованию двойных перерывов. Работает для точной данной проблемы, но не для фактического вопроса.
Даккарон

@Dakkaron Вы уверены, что правильно поняли код? Код действительно решает вопрос OPs, и ломает аналогично запросу. Однако он не разбивает несколько циклов, а использует условие else, чтобы заменить необходимость удвоения разрыва.
Праздник

Насколько я понимаю, вопрос был, How to break out of multiple loops in Python?и ответ должен был быть "Это не работает, попробуйте что-нибудь еще". Я знаю, что это исправляет точный приведенный пример ОП, но не отвечает на их вопрос.
Даккарон

@Dakkaron, посмотрите формулировку проблемы под кодом, и, на мой взгляд, она действительно отвечает на вопрос ОП.
праздник

2

Другой способ сократить вашу итерацию до одноуровневого цикла - использовать генераторы, как также указано в ссылке на Python.

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

Вы можете масштабировать его до любого количества уровней для цикла

Недостатком является то, что вы больше не можете пробить только один уровень. Это все или ничего.

Другим недостатком является то, что он не работает с циклом while. Первоначально я хотел опубликовать этот ответ на Python - `break` из всех циклов, но, к сожалению, он закрыт как дубликат этого


1
Это работает и для циклов while, вам нужно только написать свой генератор как def (с yield), а не как понимание.
Veky

Да, спикер PyCon заявляет, что даже принятый ответ @ RobertRossney не является действительно Pythonic, но генератор - это правильный способ разорвать несколько циклов. (Я бы рекомендовал посмотреть все видео!)
Post169

2

Моя причина приехать сюда в том, что у меня был внешний цикл и внутренний цикл, например, так:

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

Как видите, на самом деле он не перейдет к следующему x, а вместо этого перейдет к следующему y.

то, что я нашел, чтобы решить эту проблему, это просто дважды запустить массив:

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

Я знаю, что это был конкретный случай вопроса ОП, но я публикую его в надежде, что он поможет кому-то по-другому взглянуть на свою проблему, оставив при этом все просто.


Это, вероятно, не Python. Какой тип массива? Вероятно, список, но что он содержит? Даже если он содержит целые числа, array.pop (x), вероятно, не будет делать то, что вы хотите.
Veky

Неплохо подмечено. Я не могу найти код, на который я ссылался. Для любого, кто читает это, array.pop (i) «Удаляет элемент с индексом i из массива и возвращает его». согласно документации питона. Таким образом, нужно было бы получить индекс элемента x в массиве, чтобы этот код работал должным образом. Существует также функция array.remove (x), которая будет делать то, что ожидается. Я исправлю свой ответ выше, чтобы исправить эту ошибку. Это предполагает, что второй массив не содержит дубликатов, так как array.remove (x) удалит только первый найденный экземпляр x.
Натан Гарабедян

Хорошо, тогда я понял. В этом случае простое использование breakвместо того, continueчтобы делать то, что вы хотите, не так ли? :-)
Veky

Да, для эффективности и ясности, вы, вероятно, захотите использовать break в этих примерах вместо продолжения. :)
Натан Гарабедян

2

Попробуйте использовать бесконечный генератор.

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

Используя функцию:

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

Попробуйте запустить приведенные выше коды, также закомментировав их return.

Без использования какой-либо функции:

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

Теперь запустите приведенные выше коды как есть, а затем попробуйте запустить, закомментировав каждую строку, содержащую по breakодной, снизу.


2

Простой способ превратить несколько циклов в один разрывный цикл - это использовать 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!

Вы должны индексировать свои объекты, в отличие от возможности явно перебирать значения, но, по крайней мере, в простых случаях это кажется примерно в 2-20 раз проще, чем большинство предлагаемых ответов.


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

вероятно, подойдет маленький трюк, как показано ниже, если не предпочитаете рефакториал в функцию

добавлена ​​1 переменная break_level для управления условием цикла 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

Вы можете определить переменную (например, break_statement ), а затем изменить ее на другое значение при возникновении условия двух разрывов и использовать его в операторе if для выхода из второго цикла.

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

Хороший момент, однако на каждом из уровней выше нашего внутреннего уровня интереса нам нужно будет сканировать эту переменную. Очень плохо, что в языке нет инструкции GoTo с точки зрения производительности.
Анатолий Алексеев

1

Я хотел бы напомнить вам, что функции в Python могут быть созданы прямо в середине кода и могут прозрачно обращаться к окружающим переменным для чтения и с помощью nonlocalили globalдекларации для записи.

Таким образом, вы можете использовать функцию в качестве «разрушаемой структуры управления», определяя место, куда вы хотите вернуться:

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

Решения в 2 пути

С примером: эти две матрицы равны / одинаковы?
matrix1 и matrix2 имеют одинаковый размер, n, 2 размерных матрицы.

Первое решение , без функции

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

Второе решение , с функцией
Это окончательное решение по моему делу

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

Хорошего дня!


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

Надеюсь, это поможет:

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

Вот реализация, которая, кажется, работает:

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)

Единственным недостатком является то, что вы должны определить break_перед циклами.


0

Нет способа сделать это на уровне языка. В некоторых языках есть переход, в других есть перерыв, который принимает аргумент, в Python - нет.

Лучшие варианты:

  1. Установите флаг, который проверяется внешним циклом, или установите условие внешнего цикла.

  2. Поместите цикл в функцию и используйте return, чтобы разорвать все циклы одновременно.

  3. Переформулируйте свою логику.

Кредит Вивеку Нагараджану, программисту с 1987 года


Используя функцию

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

Используя флаг

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

Похожий на предыдущий, но более компактный. (Логические числа просто числа)

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
Это выглядит довольно уродливо и затрудняет понимание кода по сравнению с предыдущим. Кроме того, это неправильно. Он пропускает фактическую проверку допустимости ввода и прерывается после 1 цикла.
Эрик

-3

Поскольку этот вопрос стал стандартным вопросом для разбиения на определенный цикл, я хотел бы дать свой ответ с примером, используя Exception .

Хотя в конструкции с многократным циклом не существует метки с именем разрыв цикла, мы можем использовать определяемые пользователем исключения для разбиения на определенный цикл по нашему выбору. Рассмотрим следующий пример, где мы будем печатать все числа до 4 цифр в системе нумерации 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

Когда мы печатаем выходные данные, мы никогда не получим никакого значения, единичное место которого равно 4. В этом случае мы не отрываемся ни от одного цикла, который BreakLoop(4)возникает и захватывается в том же цикле. Точно так же, всякий раз, когда в десятке есть 3, мы используем третий цикл BreakLoop(3). Когда сто мест имеет 5, мы входим во второй цикл, BreakLoop(2)а когда в тысяче мест 2, мы в первый циклBreakLoop(1) .

Короче говоря, поднимите свое Исключение (встроенное или определенное пользователем) во внутренних циклах и перехватите его в цикле, откуда вы хотите возобновить управление. Если вы хотите выйти из всех циклов, поймайте исключение за пределами всех циклов. (Я не показал этот случай в примере).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.