如何跳出多重循环?
给出以下代码(不起作用):
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
有没有办法让它工作? 或者,如果用户满意,我是否必须进行一项检查以打破输入循环,然后进行另一项更有限的检查以在外部循环中一起打破?
Given the following code (that doesn't work):
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
Is there a way to make this work? Or do I have do one check to break out of the input loop, then another, more limited, check in the outside loop to break out all together if the user is satisfied?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
我的第一直觉是将嵌套循环重构为函数并使用 return 来突破。
My first instinct would be to refactor the nested loop into a function and use
return
to break out.这是另一种简短的方法。 缺点是你只能打破外层循环,但有时这正是你想要的。
这使用了 for / else 构造,解释如下: 为什么python 在 for 和 while 循环之后使用“else”?
关键见解:它只是看起来好像外部循环总是中断。 但是如果内部循环不中断,外部循环也不会中断。
continue
语句就是这里的魔力。 它位于 for-else 子句中。 根据定义,如果没有内部中断,就会发生这种情况。 在这种情况下,继续
巧妙地绕过了外部中断。Here's another approach that is short. The disadvantage is that you can only break the outer loop, but sometimes it's exactly what you want.
This uses the for / else construct explained at: Why does python use 'else' after for and while loops?
Key insight: It only seems as if the outer loop always breaks. But if the inner loop doesn't break, the outer loop won't either.
The
continue
statement is the magic here. It's in the for-else clause. By definition that happens if there's no inner break. In that situationcontinue
neatly circumvents the outer break.PEP 3136 建议标记为“中断/继续”。 Guido 拒绝了它,因为“代码太复杂了,需要这个功能非常罕见”。 不过,PEP 确实提到了一些解决方法(例如异常技术),而 Guido 认为在大多数情况下使用 return 进行重构会更简单。
PEP 3136 proposes labeled break/continue. Guido rejected it because "code so complicated to require this feature is very rare". The PEP does mention some workarounds, though (such as the exception technique), while Guido feels refactoring to use return will be simpler in most cases.
首先,普通逻辑是有帮助的。
如果由于某种原因无法制定终止条件,则例外是一个后备计划。
对于这个具体示例,可能不需要例外。
另一方面,在字符模式应用程序中我们经常有“Y”、“N”和“Q”选项。 对于“Q”选项,我们希望立即退出。 那就更特别了。
First, ordinary logic is helpful.
If, for some reason, the terminating conditions can't be worked out, exceptions are a fall-back plan.
For this specific example, an exception may not be necessary.
On other other hand, we often have "Y", "N" and "Q" options in character-mode applications. For the "Q" option, we want an immediate exit. That's more exceptional.
引入一个新变量,将其用作“循环断路器”。 首先为其分配一些内容(False、0 等),然后在外循环内部,在中断之前将值更改为其他内容(True、1、...)。 循环退出后,让“父”循环检查该值。 让我演示一下:
如果你有一个无限循环,这是唯一的出路; 对于其他循环执行速度确实要快得多。 如果您有许多嵌套循环,这也适用。 您可以退出全部或仅退出一些。 无限可能! 希望这有帮助!
Introduce a new variable that you'll use as a 'loop breaker'. First assign something to it(False,0, etc.), and then, inside the outer loop, before you break from it, change the value to something else(True,1,...). Once the loop exits make the 'parent' loop check for that value. Let me demonstrate:
If you have an infinite loop, this is the only way out; for other loops execution is really a lot faster. This also works if you have many nested loops. You can exit all, or just a few. Endless possibilities! Hope this helped!
我倾向于认为,重构为函数通常是这种情况的最佳方法,但是当您确实需要打破嵌套循环时,这里有一个有趣的异常引发方法变体@S.Lott 描述的。 它使用 Python 的
with
语句来使异常引发看起来更好一些。 定义一个新的上下文管理器(您只需执行一次):现在您可以按如下方式使用此上下文管理器:
优点:(1) 它稍微干净一些(没有显式的 try- except 块),并且 (2) 您会得到一个为每次使用
nested_break
定制Exception
子类; 无需每次都声明自己的 Exception 子类。I tend to agree that refactoring into a function is usually the best approach for this sort of situation, but for when you really need to break out of nested loops, here's an interesting variant of the exception-raising approach that @S.Lott described. It uses Python's
with
statement to make the exception raising look a bit nicer. Define a new context manager (you only have to do this once) with:Now you can use this context manager as follows:
Advantages: (1) it's slightly cleaner (no explicit try-except block), and (2) you get a custom-built
Exception
subclass for each use ofnested_break
; no need to declare your ownException
subclass each time.首先,您还可以考虑将获取和验证输入的过程设为函数; 在该函数中,如果值正确,您可以返回该值,如果不正确,则在 while 循环中继续旋转。 这基本上消除了您解决的问题,并且通常可以应用于更一般的情况(打破多个循环)。 如果您绝对必须在代码中保留此结构,并且确实不想处理簿记布尔值...
您还可以按以下方式使用 goto (使用 这里):
我知道,我知道,“你不应该使用 goto”之类的,但它在奇怪的情况下效果很好像这样的情况。
First, you may also consider making the process of getting and validating the input a function; within that function, you can just return the value if its correct, and keep spinning in the while loop if not. This essentially obviates the problem you solved, and can usually be applied in the more general case (breaking out of multiple loops). If you absolutely must keep this structure in your code, and really don't want to deal with bookkeeping booleans...
You may also use goto in the following way (using an April Fools module from here):
I know, I know, "thou shalt not use goto" and all that, but it works well in strange cases like this.
要打破多个嵌套循环,而不重构为函数,请使用带有内置 StopIteration 异常:
请参阅 此讨论关于使用 goto 语句来打破嵌套循环。
To break out of multiple nested loops, without refactoring into a function, make use of a "simulated goto statement" with the built-in StopIteration exception:
See this discussion on the use of goto statements for breaking out of nested loops.
或类似的东西。
您可以在内部循环中设置一个变量,并在内部循环退出后立即在外部循环中检查它,如果合适则中断。 我有点喜欢 GOTO 方法,前提是你不介意使用愚人节笑话模块 - 它不是 Pythonic,但它确实有意义。
or something like that.
You could set a variable in the inner loop, and check it in the outer loop immediately after the inner loop exits, breaking if appropriate. I kind of like the GOTO method, provided you don't mind using an April Fool's joke module - it’s not Pythonic, but it does make sense.
这不是最漂亮的方法,但在我看来,这是最好的方法。
我很确定您也可以在这里使用递归来解决一些问题,但我不知道这对您来说是否是一个不错的选择。
This isn't the prettiest way to do it, but in my opinion, it's the best way.
I'm pretty sure you could work out something using recursion here as well, but I don't know if that's a good option for you.
如果两个条件都为真,则继续循环。
我认为这是一种更Pythonic的方式:
Keep looping if two conditions are true.
I think this is a more Pythonic way:
信用
使用函数
使用标志
Credit
Using Function
Using flag
将循环逻辑分解为一个迭代器,该迭代器生成循环变量并在完成后返回 - 这是一个简单的迭代器,它将图像布置在行/列中,直到我们没有图像或没有地方放置它们:
这有一个优点分解复杂的循环逻辑和处理......
Factor your loop logic into an iterator that yields the loop variables and returns when done -- here is a simple one that lays out images in rows/columns until we're out of images or out of places to put them:
This has the advantage of splitting up the complicated loop logic and the processing...
将多个循环转变为单个可破坏循环的一种简单方法是使用 numpy.ndindex 。
您必须对对象进行索引,而不是能够显式地迭代值,但至少在简单的情况下,它似乎比大多数建议的答案简单 2-20 倍。
An easy way to turn multiple loops into a single, breakable loop is to use
numpy.ndindex
You do have to index into your objects, as opposed to being able to iterate through the values explicitly, but at least in simple cases it seems to be approximately 2-20 times simpler than most of the answers suggested.
Python
while ... else
结构中有一个隐藏的技巧,可以用来模拟双中断,而无需进行太多代码更改/添加。 本质上,如果while
条件为 false,就会触发else
块。continue
或break
异常均不会触发else
块。 有关详细信息,请参阅“Python while 语句的 Else 子句”的答案,或 Python 文档 while (v2.7)。唯一的缺点是您需要将双重中断条件移至 while 条件(或添加标志变量)。
for
循环也存在这种情况的变体,其中else
块在循环完成后触发。There is a hidden trick in the Python
while ... else
structure which can be used to simulate the double break without much code changes/additions. In essence if thewhile
condition is false, theelse
block is triggered. Neither exceptions,continue
orbreak
trigger theelse
block. For more information see answers to "Else clause on Python while statement", or Python doc on while (v2.7).The only downside is that you need to move the double breaking condition into the
while
condition (or add a flag variable). Variations of this exists also for thefor
loop, where theelse
block is triggered after loop completion.在这种情况下,正如其他人所指出的那样,功能分解是正确的选择。 Python 3 中的代码:
In this case, as pointed out by others as well, functional decomposition is the way to go. Code in Python 3:
通过使用函数:
尝试通过注释掉
return
来运行上述代码。不使用任何函数:
现在,首先按原样运行上述代码,然后通过从底部开始一次注释掉包含
break
的每一行来尝试运行。By using a function:
Try running the above codes by commenting out the
return
as well.Without using any function:
Now, run the above codes as is first and then try running by commenting out each line containing
break
one at a time from the bottom.将迭代减少为单级循环的另一种方法是使用生成器,如 python 参考
您可以将其扩展到任意数量的循环级别。
缺点是您不能再只中断单个级别。 要么全有,要么全无。
另一个缺点是它不能与 while 循环一起使用。 我最初想在 Python - `break` 脱离所有循环 但不幸的是,它作为这个的重复而被关闭
Another way of reducing your iteration to a single-level loop would be via the use of generators as also specified in the python reference
You could scale it up to any number of levels for the loop
The downside is that you can no longer break only a single level. It's all or nothing.
Another downside is that it doesn't work with a while loop. I originally wanted to post this answer on Python - `break` out of all loops but unfortunately that's closed as a duplicate of this one
我想提醒您,Python 中的函数可以在代码中间创建,并且可以透明地访问周围的变量以供读取,并且可以使用
nonlocal
或global
声明用于写作。因此,您可以使用函数作为“可破坏的控制结构”,定义您想要返回的位置:
I'd like to remind you that functions in Python can be created right in the middle of the code and can access the surrounding variables transparently for reading and with
nonlocal
orglobal
declaration for writing.So you can use a function as a "breakable control structure", defining a place you want to return to:
尝试使用无限发生器。
Try using an infinite generator.
这是一个似乎有效的实现:
唯一的缺点是您必须在循环之前定义
break_
。Here's an implementation that seems to work:
The only draw back is that you have to define
break_
before the loops.我个人会做的是使用一个布尔值,当我准备好打破外循环时进行切换。 例如
What I would personally do is use a boolean that toggles when I am ready to break out the outer loop. For example
两种解决方案
举个例子:这两个矩阵相等/相同吗?
矩阵 1 和矩阵 2 是相同大小的 n 二维矩阵。
第一个解决方案,没有函数
第二个解决方案,有函数
这是我的案例的最终解决方案。
Solutions in two ways
With an example: Are these two matrices equal/same?
matrix1 and matrix2 are the same size, n, two-dimensional matrices.
First solution, without a function
Second solution, with a function
This is the final solution for my case.
如果不喜欢重构到函数中
添加 1 个break_level 变量来控制 while 循环条件,可能像下面这样的小技巧会起作用
probably little trick like below will do if not prefer to refactorial into function
added 1 break_level variable to control the while loop condition
您可以定义一个变量(例如 break_statement ),然后在发生两次中断条件时将其更改为不同的值,并在 if 语句中使用它来从第二个循环中中断。
You can define a variable( for example break_statement ), then change it to a different value when two-break condition occurs and use it in if statement to break from second loop also.
我来这里的原因是我有一个外循环和一个内循环,如下所示:
如您所见,它实际上不会转到下一个 x,而是会转到下一个 y。
我发现解决这个问题的方法就是运行两次数组:
我知道这是OP问题的一个具体情况,但我发布它是希望它能帮助人们以不同的方式思考他们的问题,同时保持事情简单。
My reason for coming here is that i had an outer loop and an inner loop like so:
As you can see, it won't actually go to the next x, but will go to the next y instead.
what i found to solve this simply was to run through the array twice instead:
I know this was a specific case of OP's question, but I am posting it in the hope that it will help someone think about their problem differently while keeping things simple.
希望这有帮助:
Hopefully this helps:
我最近遇到了这个问题,想要避免重复的 return 语句,这会隐藏逻辑错误,所以查看了 @yak 的想法。 这在嵌套 for 循环中效果很好,但不是很优雅。 另一种方法是在下一个循环之前检查条件:
这可能不适用于所有地方,但具有适应性,并且如果需要,具有允许重复条件而不是潜在结果的优点。
I came across this recently and, wanting to avoid a duplicate return statement, which can conceal logical errors, looked at @yak's idea. This works well within nested for loops but is not very elegant. An alternative is to check for the condition before the next loop:
This might not work everywhere but is adaptable and, if required, has the advantage of allowing the condition to be duplicated rather than a potential result.