Нарушение вложенных циклов

Возможный дубликат:
Как вырваться из нескольких циклов в Python?

Есть ли более простой способ вырваться из вложенных циклов, чем бросать исключение? (В Perl вы можете давать метки для каждого цикла и, по крайней мере, продолжать внешний цикл.)

for x in range(10):
    for y in range(10):
        print x*y
        if x*y > 50:
            "break both loops"

I.e., есть ли лучший способ, чем:

class BreakIt(Exception): pass

try:
    for x in range(10):
        for y in range(10):
            print x*y
            if x*y > 50:
                raise BreakIt
except BreakIt:
    pass

Ответ 1

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

В сообщении , г-н ван Россум упоминает использование return, что действительно разумно и что-то, что мне нужно запомнить лично.:)

Ответ 2

for x in xrange(10):
    for y in xrange(10):
        print x*y
        if x*y > 50:
            break
    else:
        continue  # only executed if the inner loop did NOT break
    break  # only executed if the inner loop DID break

То же самое работает для более глубоких циклов:

for x in xrange(10):
    for y in xrange(10):
        for z in xrange(10):
            print x,y,z
            if x*y*z == 30:
                break
        else:
            continue
        break
    else:
        continue
    break

Ответ 3

Если вы можете извлечь код цикла в функцию, оператор return можно использовать для выхода из самого внешнего цикла в любое время.

def foo():
    for x in range(10):
        for y in range(10):
            print(x*y)
            if x*y > 50:
                return
foo()

Если вам трудно извлечь эту функцию, вы можете использовать внутреннюю функцию, как предполагает @bjd2385, например,

def your_outer_func():
    ...
    def inner_func():
        for x in range(10):
            for y in range(10):
                print(x*y)
                if x*y > 50:
                    return
    inner_func()
    ...

Ответ 4

Используйте itertools.product!

from itertools import product
for x, y in product(range(10), range(10)):
    #do whatever you want
    break

Вот ссылка на itertools.product в документации по python: http://docs.python.org/library/itertools.html#itertools.product

Вы также можете зациклить понимание массива с двумя форсами в нем, и разбить, когда захотите.

>>> [(x, y) for y in ['y1', 'y2'] for x in ['x1', 'x2']]
[
    ('x1', 'y1'), ('x2', 'y1'),
    ('x1', 'y2'), ('x2', 'y2')
]

(отформатировано для ясности)

Ответ 5

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

    x_loop_must_break = False
    for x in range(10):
        for y in range(10):
            print x*y
            if x*y > 50:
                x_loop_must_break = True
                break
        if x_loop_must_break: break

Ответ 6

Если вы собираетесь создать исключение, вы можете создать исключение StopIteration. Это, по крайней мере, сделает очевидным намерение.

Ответ 7

Вы также можете реорганизовать свой код для использования генератора. Но это не может быть решением для всех типов вложенных циклов.

Ответ 8

В этом конкретном случае вы можете объединить циклы с современным python (3.0 и, возможно, 2.6), используя itertools.product.

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