Як вирватися з декількох петель?


479

Враховуючи такий код (який не працює):

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

використання винятку може бути простішим, коли ви повинні поступатися замість того, щоб використовувати return, однак, мабуть, вам слід використовувати itertools.islice () у такому випадку.
Роберт Кінг

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

7
Я погоджуюся, що прагнення до використання return- це правильний підхід. І міркування полягає в тому, що, згідно з дзен Питона , «квартира краще, ніж вкладена». Тут у нас є три рівні гніздування, і якщо це починає заважати, саме час зменшити гніздування або принаймні витягнути все гніздування у свою функцію.
Lutz Prechelt

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' після і для циклів while і while?

Основне розуміння: лише здається , що зовнішня петля завжди ламається. Але якщо внутрішня петля не зламається, зовнішня петля також не буде.

continueЗаява магія тут. Це в пункті for-else. За визначенням, що відбувається, якщо немає внутрішнього розриву. У цій ситуації continueакуратно обходить зовнішній розрив.


6
@eugeney Чому ні? Перший розрив вийде із внутрішньої петлі.
Навін

5
@eugeney Я відчуваю, що мені щось тут не вистачає. Чи можете ви розмістити приклад?
Навін

4
@Mingliang, який може тривати до продовження.
Балдрік

1
Отримав це з відео Реймонда Хеттінгера, youtu.be/OSGv2VnC0go?t=971 , прочитайте заяви "else", приєднані до циклів, як "no_break", тоді це стає легше зрозуміти.
Амбарееш

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

148

PEP 3136 пропонує маркувати перерву / продовжувати. Гвідо відхилив це, оскільки "такий складний код вимагати цієї функції дуже рідко". Хоча PEP згадує деякі шляхи вирішення (наприклад, техніка виключень), тоді як Гвідо вважає, що рефакторинг на використання повернення буде більш простим у більшості випадків.


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

10
break; breakбуло б непогано.
PyRulez

5
@Jeyekomon Проблема полягає в тому, що вам не потрібно 3 або більше вкладених циклів, щоб це було проблемою. 2 вкладені петлі досить поширені
Jon

6
"Код настільки складний, щоб вимагати цієї функції, дуже рідко". Але якщо ви коли-небудь будете використовувати цей складний код, відсутність мічених циклів зробить це ще складніше, оскільки вам потрібно вручну переправити breakчерез усі петлі. Дурний.
BallpointBen

3
Мабуть, я можу редагувати публікацію лише протягом 5 хвилин (минуло 6). Отже, ось мій відредагований пост: Мої 2 копійки: Perl позначив перерву (але називає це "останньою") та "наступний", щоб перейти безпосередньо до наступної ітерації. Це зовсім не рідко - я ним користуюся постійно. Я абсолютно новий в 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
Взагалі, використання пробних блоків для будь-якого іншого, ніж винятки, дуже нахмуриться. Спробні блоки спеціально розроблені для обробки помилок, і використовувати їх для дивного потоку управління не дуже добре, стилістично.
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) вона трохи чистіша (немає явного спроби, крім блоку), і (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" зі вбудованим винятком StopIteration :

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

except StopIteration: pass

Дивіться цю дискусію щодо використання операторів goto для виривання вкладених циклів.


1
Це виглядає набагато приємніше, ніж створювати власний клас для обробки винятку, і виглядає дуже чисто. Чи є причина, що я не повинен цього робити?
mgjk

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

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

Я впевнений, що ви могли б щось розробити, використовуючи і рекурсію, але я не знаю, якщо це хороший варіант для вас.


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

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умовах пропустити дві петлі, але достатньо лише однієї.
Mauro Aspé

2
@MatthewScharley Я думаю, що це показати, що це працює в вкладених петлях.
обробляти

@ MauroAspé це не буде точно робити те, що вимагає ОП. він все одно виконає весь зовнішній цикл, але мета полягає в тому, що якщо ви
перервете

@yamm Не могли б це вирішити з a 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 doc on 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стан (або додати змінну прапора). Варіації цього існують і для forциклу, де elseблок спрацьовує після завершення циклу.


Схоже, це не відповідає вимозі подвійних перерв. Працює для заданої проблеми, але не для фактичного питання.
Даккарон

@Dakkaron Ви впевнені, що правильно зрозуміли код? Код насправді вирішує питання щодо ОП та розбиває подібний на запит. Однак це не вимикається з декількох циклів, але використовуйте інше, щоб замінити необхідність подвоєння розриву.
holroy

З мого розуміння, питання було, How to break out of multiple loops in Python?і відповідь повинна була бути "Не працює, спробуйте щось інше". Я знаю, він фіксує точний приклад ОП, але не відповідає на їх запитання.
Даккарон

@Dakkaron, Дивіться постановку проблеми під кодом, і, на мою думку, вона дійсно відповідає на питання ОП.
holroy

2

Іншим способом зведення вашої ітерації до однорівневого циклу буде використання генераторів, як це також зазначено в довідці python

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

Ви можете масштабувати його до будь-якої кількості рівнів для циклу

Мінус у тому, що ви більше не можете розбивати лише один рівень. Це все або нічого.

Ще один недолік полягає в тому, що він не працює з циклом час. Спочатку я хотів опублікувати цю відповідь на Python - `вирвати 'з усіх циклів, але, на жаль, це закрито як дублікат цього


1
Він працює і під час циклів, вам потрібно лише записати свій генератор як def (з урожайністю), а не як розуміння.
Векі

Так, оратор в PyCon стверджує, що навіть прийнята відповідь @ Роберт Россні не є справді пітонічною, але генератор - це правильний спосіб розірвати кілька циклів. (Рекомендую переглянути все відео!)
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. Який тип масиву? Напевно, список, але що він містить? Навіть якщо він містить ints, array.pop (x), ймовірно, не буде робити те, що ви хочете.
Veky

Це хороший момент. Я не можу знайти код, на який я посилався. Для всіх, хто читає це, array.pop (i) "Вилучає елемент з індексом i з масиву та повертає його." відповідно до документації python. Тому потрібно буде отримати індекс елемента x у масиві, щоб цей код працював так, як очікувалося. Існує також функція array.remove (x), яка б виконувала те, що очікується. Я зміню свою відповідь вище, щоб виправити цю помилку. Це передбачає, що другий масив не містить дублікатів, оскільки array.remove (x) видалить лише перший екземпляр знайденого x.
Натан Гарабедян

Гаразд, тоді я розумію. У такому випадку просто використання breakзамість цього continueробитиме те, що ти хочеш, чи не так? :-)
Veky

Так, для ефективності та ясності ви, мабуть, хочете використовувати перерви, а не продовжувати в цих прикладах. :)
Натан Гарабедян

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 ), а потім змінити її на інше значення, коли виникає умова з двома перервами, і використати її, якщо оператор також перерветься з другого циклу.

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

Рішення двома способами

Прикладом: Чи рівні ці дві матриці / однакові?
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

Неможливо зробити це з мовного рівня. Деякі мови мають goto, інші мають перерву, яка бере аргументи, 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 цифр у системі нумерації базових 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)кожну тисячу місця, і ми використовуємо перший цикл BreakLoop(1).

Коротше кажучи, підніміть виняток (вбудований або визначений користувачем) у внутрішніх циклах та вловіть його у циклі, звідки ви хочете відновити свій контроль. Якщо ви хочете перерватися з усіх циклів, виловіть виняток поза всіма петлями. (Я не показав цього випадку в прикладі).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.