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

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

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

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

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

Break将中断内部循环,而 lock1将不会执行(只有在内部循环正常退出时才会运行)。

在其他语言中,你可以标记循环,然后从标记循环中断开:

然而,我拒绝它的基础上,代码如此复杂 需要这个功能是非常罕见的。在大多数情况下,存在 产生干净代码的解决方案,例如使用“ return”。 虽然我确信有一些(罕见的)真正的情况下,明确的 代码可能会因为重构而受到影响 但有两方面的因素抵销了上述影响:

  1. 添加到语言中的复杂性,永久性的。这不会影响 只有所有的 Python 实现,还有所有的源代码分析工具, 当然还有语言的所有文档。

  2. 我预计这个特性会被滥用得更多 使用正确,导致代码清晰度净减少(衡量跨 懒惰的程序员无处不在, 在你意识到之前,你的手上已经有了一个难以置信的烂摊子 莫名其妙的密码

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

我认为你可以这样做:

for ii in range(200):
restart = False
for jj in range(200, 400):
...block0...
if something:
restart = True
break
if restart:
continue
...block1...
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()

使用异常

从哲学上讲,这就是例外的作用,在必要的时候打破程序流通过结构化编程构建块(如果,为了,而)。

这样做的好处是不必将单段代码分成多个部分。如果这是您在用 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

为此创建一个特殊的异常类,这样您就不会冒险意外地关闭其他异常。

完全是另一回事

我相信还有其他的解决办法。

处理这类问题的另一种方法是使用 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

我们希望找到一些东西,然后停止内部迭代。

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

我刚做了这样的事。我的解决方案是用列表内涵代替内部 for loop。

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,并在一行中执行所有逻辑操作是很有趣的。它还避免了函数调用。

我认为实现这一点的最简单的方法之一是用 break 语句替换“ keep”,即。

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

我所知道的继续外部循环的最佳方法是使用一个作用域在外部循环下的布尔值,并中断内部循环。不过,根据用例的不同,您可能不会中断内部循环,在内部循环中继续执行外部循环隐含地表明您希望立即跳转到外部循环的第一行,并避免在内部循环中执行任何进一步的操作。这就是我添加 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}')

这种方法避免调用任何函数和处理可能的缺点。众所周知,调用函数是一个相当昂贵的操作,特别是对 Games 而言。现在想象一个深度嵌套的 for循环将运行数百万次,将其包装在函数中不会导致平滑的体验。

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

我在这种方法中发现的唯一“问题”是,break会跳出内环一次,落在 continue上,而 continue又会再跳一次。与 C 或 JavaScript 中的 goto 语句不同,这个语句有点笨拙,但对性能没有任何明显影响,因为它只会生成一条额外的指令,其运行速度与 CPU 的时钟或解释器实现一样快。