Python:继续在外循环中进行下一次迭代

Python: Continuing to next iteration in outer loop

我想知道是否有任何内置方法可以继续在python中的外循环中进行下一次迭代。 例如,考虑代码:

1
2
3
4
5
6
for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            continue
    ...block1...

我希望这个continue语句退出jj循环并转到ii循环中的下一个项目。 我可以通过其他方式实现这个逻辑(通过设置一个标志变量),但有一种简单的方法可以做到这一点,还是这就像要求太多?


1
2
3
4
5
6
7
for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            break
    else:
        ...block1...

Break将破坏内部循环,并且不会执行block1(仅当内??循环正常退出时才会运行)。


1
2
3
4
5
for i in ...:
    for j in ...:
        for k in ...:
            if something:
                # continue loop i

在一般情况下,当您有多个循环级别并且Break对您不起作用时(因为您想继续其中一个上部循环,而不是当前循环之一),您可以执行以下操作之一

将要转义的循环重构为函数

1
2
3
4
5
6
7
8
9
def inner():
    for j in ...:
        for k in ...:
            if something:
                return


for i in ...:
    inner()

缺点是您可能需要将一些变量传递给该新函数,这些变量以前在范围内。您可以将它们作为参数传递,在对象上创建实例变量(仅为此函数创建一个新对象,如果有意义),或全局变量,单例,等等(ehm,ehm)。

或者你可以将inner定义为嵌套函数,让它只捕获它需要的东西(可能会更慢?)

1
2
3
4
5
6
7
for i in ...:
    def inner():
        for j in ...:
            for k in ...:
                if something:
                    return
    inner()

使用例外

从哲学上讲,这就是例外情况,在必要时通过结构化编程构建块(if,for,while)打破程序流。

优点是您不必将单个代码分成多个部分。如果它是在用Python编写时正在设计的某种计算,那么这很好。在这个早期阶段引入抽象可能会减慢你的速度。

这种方法的坏处是,解释器/编译器作者通常认为异常是例外的,并相应地对它们进行优化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

为此创建一个特殊的异常类,这样您就不会有意外地消除其他异常的风险。

还有别的东西

我相信还有其他解决方案。


在其他语言中,您可以标记循环并从标记循环中断。 Python Enhancement Proposal(PEP)3136建议将这些添加到Python中,但Guido拒绝了它:

However, I'm rejecting it on the basis that code so complicated to
require this feature is very rare. In most cases there are existing
work-arounds that produce clean code, for example using 'return'.
While I'm sure there are some (rare) real cases where clarity of the
code would suffer from a refactoring that makes it possible to use
return, this is offset by two issues:

  • The complexity added to the language, permanently. This affects not
    only all Python implementations, but also every source analysis tool,
    plus of course all documentation for the language.

  • My expectation that the feature will be abused more than it will be
    used right, leading to a net decrease in code clarity (measured across
    all Python code written henceforth). Lazy programmers are everywhere,
    and before you know it you have an incredible mess on your hands of
    unintelligible code.

  • 所以,如果这是你希望你运气不好的话,那么看看其他答案之一,因为那里有很好的选择。


    我想你可以这样做:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for ii in range(200):
        restart = False
        for jj in range(200, 400):
            ...block0...
            if something:
                restart = True
                break
        if restart:
            continue
        ...block1...


    我认为实现这一目标的最简单方法之一是将"继续"替换为"中断"声明,即。

    1
    2
    3
    4
    5
    6
    for ii in range(200):
     for jj in range(200, 400):
        ...block0...
        if something:
            break
     ...block1...

    例如,这里是一个简单的代码,看看它究竟是如何进行的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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()。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    for ii in range(200):
        try:
            for jj in range(200, 400):
                ...block0...
                if something:
                    raise Exception()
        except Exception:
            continue
        ...block1...

    例如:

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

    结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        1-1
        1-2
        1-3
        2-1
        2-2
        2-3
        3-1
        3-2
        3-3

    假设我们想要从m循环跳转到外部n循环,如果m = 3:

    1
    2
    3
    4
    5
    6
    7
    8
    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
    2
    3
    4
    5
    6
        1-1
        1-2
        2-1
        2-2
        3-1
        3-2

    参考链接:http://www.programming-idioms.org/idiom/42/continue-outer-loop/1264/python


    我刚刚做了这样的事情。我的解决方案是用列表理解来替换内部for循环。

    1
    2
    3
    4
    5
    6
    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"运算符在布尔列表上执行逻辑OR并在一行中执行逻辑很有趣。它还避免了函数调用。


    我们想找到一些东西,然后停止内部迭代。我使用旗帜系统。

    1
    2
    3
    4
    5
    6
    7
    for l in f:
        flag = True
        for e in r:
            if flag==False:continue
            if somecondition:
                do_something()
                flag=False