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

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

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


当前回答

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

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

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"选项,我们要立即退出。这是比较特殊的。

其他回答

我解决这个问题的方法是定义一个变量,该变量被引用来确定你是否进入下一关。在这个例子中,这个变量叫做shouldbreak。

Variable_That_Counts_To_Three=1
while 1==1:
    shouldbreak='no'
    Variable_That_Counts_To_Five=0
    while 2==2:
        Variable_That_Counts_To_Five+=1
        print(Variable_That_Counts_To_Five)
        if Variable_That_Counts_To_Five == 5:
            if Variable_That_Counts_To_Three == 3:
                shouldbreak='yes'
            break
    print('Three Counter = ' + str(Variable_That_Counts_To_Three))
    Variable_That_Counts_To_Three+=1
    if shouldbreak == 'yes':
        break

print('''
This breaks out of two loops!''')

这为您希望程序中断的确切方式提供了大量控制,允许您选择何时中断以及下降多少层。

我倾向于认为重构到函数中通常是这种情况的最佳方法,但是当您确实需要打破嵌套循环时,这里有一个有趣的异常引发方法的变体@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子类。

尽量减少对OP的问题的改变,我只是在打破第一个for循环之前添加了一个标志,并检查外部循环上的标志,看看我们是否需要再次刹车。

break_2 = False
while True:
    # Snip: print out current state
    if break_2: break
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok.lower() == "y": break_2 = True
        if break_2: break
        if ok.lower() == "n": break
    # Do more processing with menus and stuff

我来这里的原因是我有一个外循环和一个内循环,像这样:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

  do some other stuff with x

正如你所看到的,它不会去下一个x,而是去下一个y。

我发现解决这个问题的简单方法是遍历数组两次:

for x in array:
  for y in dont_use_these_values:
    if x.value==y:
      array.remove(x)  # fixed, was array.pop(x) in my original answer
      continue

for x in array:
  do some other stuff with x

我知道这是OP问题的一个具体案例,但我发布它是希望它能帮助人们以不同的方式思考他们的问题,同时保持事情简单。

以下是一个非常简短的版本: 创建名为break_out_nested.py的文件

import itertools
import sys

it = sys.modules[__name__] # this allows us to share variables with break_out_nested.py when we import it 


def bol(*args):
    condi = args[-1] # the condition function
    i = args[:-1] # all iterables 
    for p in itertools.product(*i): # itertools.product creates the nested loop
        if condi(): # if the condition is True, we return 
            return
        yield p # if not, we yield the result 

现在你只需要几行就可以打破嵌套的循环(数据来自Rafiq的例子)

from break_out_nested import it, bol # import what we have just created

# you need to create new variables as attributes of it,
# because break_out_nested has only access to these variables
it.i, it.j, it.k = 1, 1, 1
# the break condition
def cond(): return it.i % 3 == 0 and it.j % 3 == 0 and it.k % 3 == 0

# The condition will be checked in each loop 
for it.i, it.j, it.k in bol(range(1, 6, 1), range(1, 11, 2, ), range(1, 21, 4), cond):
    print(it.i, it.j, it.k)

更多的例子:

def cond(): return it.i + it.j + it.k == 777

it.i, it.j, it.k = 0, 0, 0
for it.i, it.j, it.k in bol(range(100), range(1000), range(10000), cond):
    print(it.i, it.j, it.k)




def cond(): return it.i + it.j + it.k >= 100000

it.i, it.j, it.k = 0, 0, 0
# you dont have to use it.i, it.j, it.k as the loop variables, you can
# use anything you want, but you have to update the variables somewhere
for i, j, k in bol(range(100), range(1000), range(10000), cond):
    it.i, it.j, it.k = i * 10, j * 100, k * 100
    print(it.i, it.j, it.k)