374

有没有比抛出异常更容易摆脱嵌套循环的方法?(在 Perl 中,您可以为每个循环指定标签,并至少继续一个外部循环。)

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

即,有没有比以下更好的方法:

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
4

8 回答 8

903
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
于 2009-03-17T12:27:02.140 回答
192

至少有人建议过,但也拒绝过。我认为除了重复测试或重新组织代码之外,没有其他方法。有时有点烦人。

拒绝信息中,van Rossum 先生提到 using return,这真的很明智,我个人需要记住这一点。:)

于 2009-03-17T09:27:09.077 回答
85

如果您能够将循环代码提取到函数中,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()
    ...
于 2009-03-17T12:37:59.680 回答
59

使用 itertools.product!

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

这是 python 文档中指向 itertools.product 的链接:http: //docs.python.org/library/itertools.html#itertools.product

您还可以循环遍历包含 2 个 fors 的数组推导,并随时中断。

>>> [(x, y) for y in ['y1', 'y2'] for x in ['x1', 'x2']]
[
    ('x1', 'y1'), ('x2', 'y1'),
    ('x1', 'y2'), ('x2', 'y2')
]
于 2011-10-26T17:47:19.470 回答
46

有时我使用布尔变量。天真,如果你愿意的话,但我觉得它阅读起来非常灵活和舒适。测试一个变量可以避免再次测试复杂的条件,也可以从内部循环中的几个测试中收集结果。

    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
于 2011-05-16T20:50:55.047 回答
23

如果要引发异常,可能会引发StopIteration 异常。这至少会使意图显而易见。

于 2012-08-14T00:31:38.450 回答
8

您还可以重构代码以使用生成器。但这可能不是所有类型的嵌套循环的解决方案。

于 2009-03-17T10:29:00.207 回答
3

在这种特殊情况下,您可以使用 itertools.product 将循环与现代 python(3.0 和可能 2.6)合并。

我自己将此作为经验法则,如果您嵌套了太多循环(例如,超过 2 个),您通常可以将其中一个循环提取到不同的方法中或将循环合并为一个,如下所示案子。

于 2009-03-17T09:58:34.040 回答