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

时间:2009-12-07 10:14:12

标签: python loops

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

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

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

9 个答案:

答案 0 :(得分:122)

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

Break将打破内部循环,并且不会执行block1(只有在内循环正常退出时才会运行)。

答案 1 :(得分:44)

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

使用例外

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

优点是您不必将单个代码分成多个部分。如果它是在用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

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

其他完全

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

答案 2 :(得分:37)

在其他语言中,您可以标记循环并从标记循环中断。 Python Enhancement Proposal (PEP) 3136 suggested adding these to PythonGuido rejected it

  

然而,我拒绝它是因为代码如此复杂   要求此功能非常罕见。在大多数情况下,存在   产生干净代码的解决方法,例如使用'return'。   虽然我确信有一些(罕见的)真实案例的清晰度   代码将遭受重构,使其可以使用   返回,这被两个问题所抵消:

     
      
  1. 永久性地增加了语言的复杂性。这不会影响   只有所有Python实现,但也包括每个源分析工具,   当然还有该语言的所有文档。

  2.   
  3. 我希望这个功能会被滥用   使用正确,导致代码清晰度净减少(测量结果   今后编写的所有Python代码)。懒惰的程序员无处不在,   在你知道它之前,你的手上有一个令人难以置信的混乱   无法理解的代码。

  4.   

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

答案 3 :(得分:12)

我认为你可以这样做:

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

答案 4 :(得分:1)

处理此类问题的另一种方法是使用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循环跳转到外部n循环,如果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

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

答案 5 :(得分:1)

我认为最简单的方法之一是用“ 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")

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

我只是做了这样的事情。我对此的解决方案是用列表理解替换内部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”运算符对布尔值列表进行逻辑或,然后全部执行逻辑很有趣。它还避免了函数调用。

答案 8 :(得分:0)

我所知道的继续外循环的最佳方法是使用一个布尔值,该布尔值限定在外循环下并破坏内循环。尽管根据用例您可能不会中断内循环,但在其内循环内继续外循环暗示您希望立即跳转到外循环的第一行并避免在内循环中进一步执行。这就是我添加 break 语句的原因。

for i in range(0, 6):
    should_continue = False

    for f in range(1, i * 2):
        print(f"f = {f}")
        if (not (f % 1337) or not (f % 7)):
            print(f"{f} can be divided, continue outer loop")
            should_continue = True
            # leaves inner loop
            break

    if(should_continue): continue
    # Outer loop's code goes here
    print(f'Reached outer loop\ni = {i}')

这种方法避免调用任何函数并处理可能的缺点。众所周知,调用函数是一项相当昂贵的操作,特别是对于游戏而言。现在想象一个深度嵌套的 for 循环,它将运行数百万次,将它包装在一个函数中不会带来流畅的体验。

将循环包装在异常块内也是一个坏主意,而且会比函数慢得多。这是因为 Python 需要大量的开销来触发异常机制并稍后恢复运行时状态,因此异常被设计用于异常使用。考虑到这一点,即使是一些 CPU 优化(例如 speculative execution)也不应该应用于异常块,而且可能也不会。

我在这种方法中发现的唯一“问题”是 break 会在内循环外跳一次,落在 continue 上,而 Files 会再跳一次。与 C 或 JavaScript 中的 goto 语句相比,这有点笨拙。