Python:继续外循环中的下一个迭代

问题:Python:继续外循环中的下一个迭代

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

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

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

I wanted to know if there are any built-in ways to continue to next iteration in outer loop in python. For example, consider the code:

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

I want this continue statement to exit the jj loop and goto next item in the ii loop. I can implement this logic in some other way (by setting a flag variable), but is there an easy way to do this, or is this like asking for too much?


回答 0

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

使用exceptions

从哲学上讲,这就是exceptions,在必要时,通过结构化的编程构建块(如果是,为时,为时)中断程序流。

这样做的好处是您不必将单个代码分成多个部分。如果这是您在用Python编写代码时正在设计的某种计算,那么这很好。在早期引入抽象可能会使您减速。

这种方法的坏处在于,解释器/编译器作者通常会认为异常是exceptions情况,因此会相应地对其进行优化。

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 i in ...:
    for j in ...:
        for k in ...:
            if something:
                # continue loop i

In a general case, when you have multiple levels of looping and break does not work for you (because you want to continue one of the upper loops, not the one right above the current one), you can do one of the following

Refactor the loops you want to escape from into a function

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


for i in ...:
    inner()

The disadvantage is that you may need to pass to that new function some variables, which were previously in scope. You can either just pass them as parameters, make them instance variables on an object (create a new object just for this function, if it makes sense), or global variables, singletons, whatever (ehm, ehm).

Or you can define inner as a nested function and let it just capture what it needs (may be slower?)

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

Use exceptions

Philosophically, this is what exceptions are for, breaking the program flow through the structured programming building blocks (if, for, while) when necessary.

The advantage is that you don’t have to break the single piece of code into multiple parts. This is good if it is some kind of computation that you are designing while writing it in Python. Introducing abstractions at this early point may slow you down.

Bad thing with this approach is that interpreter/compiler authors usually assume that exceptions are exceptional and optimize for them accordingly.

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

Create a special exception class for this, so that you don’t risk accidentally silencing some other exception.

Something else entirely

I am sure there are still other solutions.


回答 1

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

Break 将中断内部循环,并且不会执行block1(仅在内部循环正常退出时才会运行)。

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

Break will break the inner loop, and block1 won’t be executed (it will run only if the inner loop is exited normally).


回答 2

在其他语言中,您可以标记循环并从标记循环中中断。 Python增强提案(PEP)3136建议将它们添加到Python中,Guido拒绝了它

但是,我拒绝这样的理由是,如此复杂的代码很少需要此功能。在大多数情况下,现有的变通办法可以生成干净的代码,例如使用“返回”。虽然我确信在某些(罕见)实际情况下,代码的清晰性会受到重构的影响,从而可以使用return,但是这被两个问题抵消了:

  1. 复杂性永久地增加了语言。这不仅会影响所有Python实现,而且会影响每个源代码分析工具,当然还会影响该语言的所有文档。

  2. 我期望该功能的滥用程度将超过其正确使用的程度,从而导致代码清晰度净下降(此后对所有编写的Python代码进行衡量)。懒惰的程序员无处不在,在您不了解它之前,您就难以理解难以理解的代码。

因此,如果那是您希望自己没有运气的原因,请查看其他答案之一,因为那里有不错的选择。

In other languages you can label the loop and break from the labelled loop. Python Enhancement Proposal (PEP) 3136 suggested adding these to Python but Guido rejected it:

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:

  1. 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.

  2. 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.

So if that’s what you were hoping for you’re out of luck, but look at one of the other answers as there are good options there.


回答 3

我认为您可以执行以下操作:

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

I think you could do something like this:

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

回答 4

我认为最简单的方法之一是用“ break”语句代替“ continue”,即

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

I think one of the easiest ways to achieve this is to replace “continue” with “break” statement,i.e.

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

For example, here is the easy code to see how exactly it goes on:

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

回答 5

解决此类问题的另一种方法是使用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

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

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-outer-loop/1264/python

Another way to deal with this kind of problem is to use Exception().

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

For example:

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

result:

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

Assuming we want to jump to the outer n loop from m loop if 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

result:

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

Reference link:http://www.programming-idioms.org/idiom/42/continue-outer-loop/1264/python


回答 6

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

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

We want to find something and then stop the inner iteration. I use a flag system.

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

回答 7

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

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”运算符对布尔值列表进行逻辑或,然后全部执行逻辑是很有趣的。它还避免了函数调用。

I just did something like this. My solution for this was to replace the interior for loop with a list comprehension.

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

where op is some boolean operator acting on a combination of ii and jj. In my case, if any of the operations returned true, I was done.

This is really not that different from breaking the code out into a function, but I thought that using the “any” operator to do a logical OR on a list of booleans and doing the logic all in one line was interesting. It also avoids the function call.