Питон: Продолжение В следующей итерации внешнего цикла


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

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

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

8 86

8 ответов:

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

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

или вы можете определить 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

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

что-то совсем другое

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

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

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

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

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

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

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

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

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

for ii in range(200):
    restart = False
    for jj in range(200, 400):
        ...block0...
        if something:
            restart = True
            break
    if restart:
        continue
    ...block1...

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

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 " для выполнения логического ИЛИ списка булевых значений и выполнения логики все в одна строчка была интересной. Это также позволяет избежать вызова функции.

Я думаю, что один из самых простых способов добиться этого-заменить "continue" на "break", т. е.

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

другой способ справиться с этой проблемой-использовать 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

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

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

for l in f:
    flag = True
    for e in r:
        if flag==False:continue
        if somecondition:
            do_something()
            flag=False