Как вырваться из нескольких циклов в Python? - PullRequest
390 голосов
/ 10 октября 2008

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

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

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

Ответы [ 29 ]

8 голосов
/ 06 ноября 2012

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

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

Не правда ли?

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

8 голосов
/ 12 апреля 2010

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

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 голосов
/ 14 октября 2015

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

3 голосов
/ 15 августа 2015

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

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

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, а вместо этого перейдет к следующему x.

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

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

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

2 голосов
/ 13 июня 2013
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
2 голосов
/ 01 декабря 2016

Другим способом сокращения вашей итерации до одноуровневого цикла было бы использование генераторов, как также указано в справочнике по питону

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

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

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

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

2 голосов
/ 05 апреля 2018

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

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 по одной снизу.

1 голос
/ 12 мая 2018

Простой способ превратить несколько циклов в один разрывный цикл - использовать 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 раз проще, чем большинство предлагаемых ответов.

1 голос
/ 22 марта 2017

Вы можете определить переменную (например, 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...