给定以下代码(不起作用):

while True:
    # Snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break 2 # This doesn't work :(
        if ok.lower() == "n": break

    # Do more processing with menus and stuff

有办法解决这个问题吗?还是我必须先检查一次,跳出输入循环,然后再检查一次,如果用户满意,再跳出外部循环?


当前回答

我倾向于认为重构到函数中通常是这种情况的最佳方法,但是当您确实需要打破嵌套循环时,这里有一个有趣的异常引发方法的变体@S。洛特。它使用Python的with语句使异常引发看起来更好一些。定义一个新的上下文管理器(你只需要这样做一次):

from contextlib import contextmanager
@contextmanager
def nested_break():
    class NestedBreakException(Exception):
        pass
    try:
        yield NestedBreakException
    except NestedBreakException:
        pass

现在你可以像下面这样使用这个上下文管理器:

with nested_break() as mylabel:
    while True:
        print "current state"
        while True:
            ok = raw_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": raise mylabel
            if ok == "n" or ok == "N": break
        print "more processing"

优点:(1)它稍微干净一些(没有显式的try-except块),并且(2)每次使用nested_break你都会得到一个定制的Exception子类;不需要每次都声明自己的Exception子类。

其他回答

我的第一反应是将嵌套循环重构为一个函数,并使用return来跳出。

PEP 3136建议标记中断/继续。Guido拒绝了它,因为“需要这个功能的复杂代码非常罕见”。不过,PEP确实提到了一些变通方法(比如异常技术),而Guido认为在大多数情况下,使用return进行重构会更简单。

如果您只需要在复杂的for循环巢中测试边缘情况,则可以抛出1/0来引发异常。我保证不会告诉任何人。当您希望快速测试深度嵌套的for循环的单个迭代,并且不想跟踪大量break语句或注释掉大量代码时,这种方法非常方便。

是的,您可以将它包装在函数中并使用return,但在某些上下文中,这可能会非常麻烦。

入门级程序员的例子:

for i in first_iter:
    for j in second_iter:
        for k in third_iter:
            print(i_want_to_run_this_once_and_stop_executing(i,j,k))
            1/0
        code_that_takes_a_long_time()
    expensive_code()

在执行大量数据预处理的大型jupyter笔记本脚本中,这尤其方便。

你可以使用一个标志来打破循环:

if found:
  break

这里,'found'是标志,你最初将它设置为False,然后在循环中使用这段代码。

found = False
for table_height in range(500):
  if found:
    break

下面是三个for循环的完整代码:

found = False
for table_height in range(500):
  if found:
    break
  for cat_height in range(500):
    if found:
      break

    for tort_height in range(500):
      equation1 = table_height + cat_height == tort_height + 170
      equation2 = table_height + tort_height == cat_height + 130
      if equation1 and equation2:
        print('table', table_height, '  cat', cat_height, '  tortoise', tort_height)
        found = True
        break

在这段代码中,如果等式1和等式2为True,它将设置'found'标志为True,并跳出最里面的for循环,它也将跳出其他两个for循环,因为'found'为True。

首先,普通的逻辑是有用的。

如果由于某种原因,终止条件无法确定,例外是一个后备计划。

class GetOutOfLoop( Exception ):
    pass

try:
    done= False
    while not done:
        isok= False
        while not (done or isok):
            ok = get_input("Is this ok? (y/n)")
            if ok in ("y", "Y") or ok in ("n", "N") : 
                done= True # probably better
                raise GetOutOfLoop
        # other stuff
except GetOutOfLoop:
    pass

对于这个特定的示例,可能不需要异常。

另一方面,在字符模式应用程序中,我们经常有“Y”、“N”和“Q”选项。对于"Q"选项,我们要立即退出。这是比较特殊的。