Как прервать выполнение нескольких циклов?
У меня есть следующий код, который не работает:
while True:
# Срез: вывод текущего состояния
while True:
ok = get_input("Все в порядке? (y/n)")
if ok.lower() == "y": break 2 # Это не работает :(
if ok.lower() == "n": break
# Продолжение обработки с меню и т.д.
Есть ли способ сделать так, чтобы это работало? Или мне нужно первым делом сделать одну проверку для выхода из цикла ввода, а затем другую, более ограниченную, проверку в внешнем цикле, чтобы выйти полностью, если пользователь удовлетворен?
5 ответ(ов)
Мой первый инстинкт — это рефакторинг вложенного цикла в отдельную функцию и использование return для выхода из неё.
Прежде всего, обычная логика может оказаться полезной.
Если по какой-то причине условия завершения не удается корректно обработать, исключения могут служить запасным планом.
class GetOutOfLoop(Exception):
pass
try:
done = False
while not done:
isok = False
while not (done or isok):
ok = get_input("Это нормально? (y/n)")
if ok in ("y", "Y") or ok in ("n", "N"):
done = True # вероятно, лучше так
raise GetOutOfLoop
# другие действия
except GetOutOfLoop:
pass
В этом конкретном примере исключение, возможно, не является необходимым.
С другой стороны, в прикладных программах в текстовом режиме часто есть опции "Y", "N" и "Q". Для опции "Q" мы хотим немедленного выхода. Это более исключительная ситуация.
Для выхода из вложенных циклов можно использовать переменную-прерывание. Сначала присвойте ей какое-либо значение (например, False или 0), а затем, внутри внешнего цикла, перед выходом измените значение на что-то другое (например, True или 1). После выхода из цикла проверьте значение переменной-прерывания в "родительском" цикле. Вот пример:
breaker = False # наша могучая переменная для выхода из цикла!
while True:
while True:
if conditionMet:
# вставьте код здесь...
breaker = True
break
if breaker: # интересная часть!
break # <--- !
Если у вас есть бесконечный цикл, это единственный способ выйти из него. Для других циклов выполнение будет гораздо быстрее. Этот подход также работает, если у вас много вложенных циклов. Вы можете выйти из всех или только из нескольких. Безграничные возможности! Надеюсь, это поможет!
Я склонен согласиться с тем, что рефакторинг в функцию обычно является лучшим подходом в подобных ситуациях, но когда вам действительно нужно выйти из вложенных циклов, вот интересный вариант подхода с выбрасыванием исключений, описанного @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("текущее состояние")
while True:
ok = input("Это нормально? (y/n)")
if ok == "y" or ok == "Y": raise mylabel
if ok == "n" or ok == "N": break
print("дальнейшая обработка")
Преимущества: (1) это немного чище (нет явного блока try-except), и (2) вы получаете кастомный подкласс Exception для каждого использования nested_break; нет необходимости объявлять свой собственный подкласс Exception каждый раз.
Ваш код реализует два вложенных цикла, которые продолжают выполнять действия до тех пор, пока переменная keeplooping равна True. Когда функция finisheddoingstuff() возвращает True, вы устанавливаете keeplooping в False, что завершает оба цикла.
Однако можно улучшить эту логику, используя флаг в внутреннем цикле и проверяя его в родительском цикле сразу после выхода из внутреннего. Пример кода может выглядеть так:
keeplooping = True
while keeplooping:
# Выполняем какие-то действия
finished_inner_loop = False
while not finished_inner_loop:
# Выполняем другие действия
if finisheddoingstuff():
finished_inner_loop = True
# Проверка условия для завершения внешнего цикла
keeplooping = not finished_inner_loop
Что касается использования конструкции GOTO — хоть это и не является "питоническим" стилем (Python не поддерживает GOTO), можно использовать различные модули-неудобства в шутливом ключе. Однако лучше придерживаться идиоматического стиля Python, чтобы сохранить чистоту и читаемость кода.
Как выйти из вложенных циклов в JavaScript?
Как изменить порядок столбцов в DataFrame?
'pip' не распознан как командa внутреннего или внешнего формата
Почему statistics.mean() работает так медленно?
Есть ли разница между поднятием экземпляра класса Exception и самого класса Exception?