Python: переход к следующей итерации во внешнем цикле - PullRequest
104 голосов
/ 07 декабря 2009

Я хотел знать, есть ли какие-нибудь встроенные способы для перехода к следующей итерации во внешнем цикле в python. Например, рассмотрим код:

for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            continue
    ...block1...

Я хочу, чтобы этот оператор continue выходил из цикла jj и переходил к следующему элементу в цикле ii. Я могу реализовать эту логику другим способом (установив переменную flag), но есть ли простой способ сделать это, или это все равно что просить слишком много?

Ответы [ 8 ]

125 голосов
/ 07 декабря 2009
for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            break
    else:
        ...block1...

Break прервет внутренний цикл, и block1 не будет выполнен (он будет работать только при нормальном выходе из внутреннего цикла).

46 голосов
/ 04 декабря 2016
for i in ...:
    for j in ...:
        for k in ...:
            if something:
                # continue loop i

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

Рефакторинг циклов, из которых вы хотите выйти в функцию

def inner():
    for j in ...:
        for k in ...:
            if something:
                return


for i in ...:
    inner()

Недостатком является то, что вам может потребоваться передать этой новой функции некоторые переменные, которые ранее находились в области видимости. Вы можете либо просто передать их как параметры, сделать их переменными экземпляра объекта (создать новый объект только для этой функции, если это имеет смысл), либо глобальными переменными, синглетами и т. Д. (Эм, эм).

Или вы можете определить inner как вложенную функцию и позволить ей просто захватывать то, что ей нужно (может быть медленнее?)

for i in ...:
    def inner():
        for j in ...:
            for k in ...:
                if something:
                    return
    inner()

Использовать исключения

С точки зрения философии, это то, для чего нужны исключения, когда необходимо разорвать поток программы через строительные блоки структурированного программирования (если, для, в то время).

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

Недостаток этого подхода в том, что авторы интерпретатора / компилятора обычно предполагают, что исключения являются исключительными, и оптимизируют их соответственно.

class ContinueI(Exception):
    pass


continue_i = ContinueI()

for i in ...:
    try:
        for j in ...:
            for k in ...:
                if something:
                    raise continue_i
    except ContinueI:
        continue

Создайте для этого специальный класс исключений, чтобы вы не рискнули случайно отключить какое-то другое исключение.

Что-то еще целиком

Я уверен, что есть и другие решения.

37 голосов
/ 07 декабря 2009

На других языках вы можете пометить петлю и оторваться от помеченной петли. Python Enhancement Proposal (PEP) 3136 предложил добавить их в Python , но Гвидо отклонил его :

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

  1. Сложность, добавленная к языку, навсегда. Это не влияет только все реализации Python, но также и каждый инструмент анализа исходного кода, плюс конечно вся документация по языку.

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

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

12 голосов
/ 05 августа 2010

Я думаю, вы могли бы сделать что-то вроде этого:

for ii in range(200):
    restart = False
    for jj in range(200, 400):
        ...block0...
        if something:
            restart = True
            break
    if restart:
        continue
    ...block1...
1 голос
/ 20 августа 2018

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

for ii in range(200):
 for jj in range(200, 400):
    ...block0...
    if something:
        break
 ...block1...       

Например, вот простой код, чтобы увидеть, как именно это происходит:

for i in range(10):
    print("doing outer loop")
    print("i=",i)
    for p in range(10):
        print("doing inner loop")
        print("p=",p)
        if p==3:
            print("breaking from inner loop")
            break
    print("doing some code in outer loop")
1 голос
/ 30 июня 2017

Другим способом решения этой проблемы является использование Exception ().

for ii in range(200):
    try:
        for jj in range(200, 400):
            ...block0...
            if something:
                raise Exception()
    except Exception:
        continue
    ...block1...

Например:

for n in range(1,4):
    for m in range(1,4):
        print n,'-',m

результат:

    1-1
    1-2
    1-3
    2-1
    2-2
    2-3
    3-1
    3-2
    3-3

Предполагая, что мы хотим перейти к внешнему n-циклу из m-цикла, если m = 3:

for n in range(1,4):
    try:
        for m in range(1,4):
            if m == 3:
                raise Exception()            
            print n,'-',m
    except Exception:
        continue

результат:

    1-1
    1-2
    2-1
    2-2
    3-1
    3-2

Ссылка: http://www.programming -idioms.org / idiom / 42 / continue-external-loop / 1264 / python

0 голосов
/ 19 июня 2018

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

for ii in range(200):
    done = any([op(ii, jj) for jj in range(200, 400)])
    ...block0...
    if done:
        continue
    ...block1...

где op - некоторый логический оператор, действующий на комбинацию ii и jj. В моем случае, если какая-либо из операций вернула true, я был сделан.

На самом деле это ничем не отличается от разбиения кода на функцию, но я подумал, что использование оператора «any» для выполнения логического ИЛИ в списке логических значений и выполнения логики в одной строке было интересно. Это также позволяет избежать вызова функции.

0 голосов
/ 07 декабря 2017

Мы хотим найти что-то и затем остановить внутреннюю итерацию. Я использую систему флагов.

for l in f:
    flag = True
    for e in r:
        if flag==False:continue
        if somecondition:
            do_something()
            flag=False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...