标签归档:control-flow

如何退出if子句

问题:如何退出if子句

有哪些方法可以过早退出if子句?

有时候,我在编写代码时希望将一条break语句放在一个if子句中,只是要记住,这些语句只能用于循环。

让我们以以下代码为例:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
   # more code here

我可以想到一种方法:假设退出情况发生在嵌套的if语句内,请将其余代码包装在一个大else块中。例:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   else:
       ...
       if condition_b:
           # do something
           # and then exit the outer if block
       else:
           # more code here

问题是更多的退出位置意味着更多的嵌套/缩进代码。

另外,我可以编写我的代码以使if子句尽可能小,并且不需要任何退出。

有人知道退出if子句的好/更好的方法吗?

如果存在任何关联的else-if和else子句,我认为退出将跳过它们。

What sorts of methods exist for prematurely exiting an if clause?

There are times when I’m writing code and want to put a break statement inside of an if clause, only to remember that those can only be used for loops.

Lets take the following code as an example:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
   # more code here

I can think of one way to do this: assuming the exit cases happen within nested if statements, wrap the remaining code in a big else block. Example:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   else:
       ...
       if condition_b:
           # do something
           # and then exit the outer if block
       else:
           # more code here

The problem with this is that more exit locations mean more nesting/indented code.

Alternatively, I could write my code to have the if clauses be as small as possible and not require any exits.

Does anyone know of a good/better way to exit an if clause?

If there are any associated else-if and else clauses, I figure that exiting would skip over them.


回答 0

(此方法适用于ifs,多个嵌套循环和您break不易使用的其他构造。)

将代码包装在自己的函数中。代替break使用return

例:

def some_function():
    if condition_a:
        # do something and return early
        ...
        return
    ...
    if condition_b:
        # do something else and return early
        ...
        return
    ...
    return

if outer_condition:
    ...
    some_function()
    ...

(This method works for ifs, multiple nested loops and other constructs that you can’t break from easily.)

Wrap the code in its own function. Instead of break, use return.

Example:

def some_function():
    if condition_a:
        # do something and return early
        ...
        return
    ...
    if condition_b:
        # do something else and return early
        ...
        return
    ...
    return

if outer_condition:
    ...
    some_function()
    ...

回答 1

goto导入goto,标签

如果有条件:
   ...
   如果condition_a:
       # 做一点事
       #然后退出外部if块
       转到.end
   ...
   如果condition_b:
       # 做一点事
       #然后退出外部if块
       转到.end
   #更多代码在这里

标签.end

(请不要实际使用它。)

from goto import goto, label

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
       goto .end
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
       goto .end
   # more code here

label .end

(Don’t actually use this, please.)


回答 2

while some_condition:
   ...
   if condition_a:
       # do something
       break
   ...
   if condition_b:
       # do something
       break
   # more code here
   break
while some_condition:
   ...
   if condition_a:
       # do something
       break
   ...
   if condition_b:
       # do something
       break
   # more code here
   break

回答 3

您可以使用以下方法模拟goto的功能:

try:
    # blah, blah ...
    # raise MyFunkyException as soon as you want out
except MyFunkyException:
    pass

免责声明:我只是想提醒您注意以这种方式做事的可能性,而在正常情况下,我绝不认为这样做是合理的。正如我在对该问题的评论中所提到的那样,到目前为止,最好构造代码以便避免拜占庭条件。:-)

You can emulate goto’s functionality with exceptions:

try:
    # blah, blah ...
    # raise MyFunkyException as soon as you want out
except MyFunkyException:
    pass

Disclaimer: I only mean to bring to your attention the possibility of doing things this way, while in no way do I endorse it as reasonable under normal circumstances. As I mentioned in a comment on the question, structuring code so as to avoid Byzantine conditionals in the first place is preferable by far. :-)


回答 4

可能是这个吗?

if some_condition and condition_a:
       # do something
elif some_condition and condition_b:
           # do something
           # and then exit the outer if block
elif some_condition and not condition_b:
           # more code here
else:
     #blah
if

may be this?

if some_condition and condition_a:
       # do something
elif some_condition and condition_b:
           # do something
           # and then exit the outer if block
elif some_condition and not condition_b:
           # more code here
else:
     #blah
if

回答 5

对于实际提出的要求,我的方法是将这些ifs放入一个单循环的循环中

while (True):
    if (some_condition):
        ...
        if (condition_a):
            # do something
            # and then exit the outer if block
            break
        ...
        if (condition_b):
            # do something
            # and then exit the outer if block
            break
        # more code here
    # make sure it is looped once
    break

测试一下:

conditions = [True,False]
some_condition = True

for condition_a in conditions:
    for condition_b in conditions:
        print("\n")
        print("with condition_a", condition_a)
        print("with condition_b", condition_b)
        while (True):
            if (some_condition):
                print("checkpoint 1")
                if (condition_a):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 2")
                    break
                print ("checkpoint 3")
                if (condition_b):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 4")
                    break
                print ("checkpoint 5")
                # more code here
            # make sure it is looped once
            break

For what was actually asked, my approach is to put those ifs inside a one-looped loop

while (True):
    if (some_condition):
        ...
        if (condition_a):
            # do something
            # and then exit the outer if block
            break
        ...
        if (condition_b):
            # do something
            # and then exit the outer if block
            break
        # more code here
    # make sure it is looped once
    break

Test it:

conditions = [True,False]
some_condition = True

for condition_a in conditions:
    for condition_b in conditions:
        print("\n")
        print("with condition_a", condition_a)
        print("with condition_b", condition_b)
        while (True):
            if (some_condition):
                print("checkpoint 1")
                if (condition_a):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 2")
                    break
                print ("checkpoint 3")
                if (condition_b):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 4")
                    break
                print ("checkpoint 5")
                # more code here
            # make sure it is looped once
            break

回答 6

一般来说,不要。如果要嵌套“ if”并从中断开,则说明这样做是错误的。

但是,如果您必须:

if condition_a:
   def condition_a_fun():
       do_stuff()
       if we_wanna_escape:
           return
   condition_a_fun()
if condition_b:
   def condition_b_fun():
       do_more_stuff()
       if we_wanna_get_out_again:
           return
   condition_b_fun()

注意,这些函数不必在if语句中声明,可以提前声明它们;)这将是一个更好的选择,因为它将避免以后再重构一个丑陋的if / then。

Generally speaking, don’t. If you are nesting “ifs” and breaking from them, you are doing it wrong.

However, if you must:

if condition_a:
   def condition_a_fun():
       do_stuff()
       if we_wanna_escape:
           return
   condition_a_fun()
if condition_b:
   def condition_b_fun():
       do_more_stuff()
       if we_wanna_get_out_again:
           return
   condition_b_fun()

Note, the functions don’t HAVE to be declared in the if statement, they can be declared in advance ;) This would be a better choice, since it will avoid needing to refactor out an ugly if/then later on.


回答 7

实际上,您所描述的是goto语句,通常会对其进行大量平移。您的第二个示例更容易理解。

但是,清洁器仍然是:

if some_condition:
   ...
   if condition_a:
       your_function1()
   else:
       your_function2()

...

def your_function2():
   if condition_b:
       # do something
       # and then exit the outer if block
   else:
       # more code here

Effectively what you’re describing are goto statements, which are generally panned pretty heavily. Your second example is far easier to understand.

However, cleaner still would be:

if some_condition:
   ...
   if condition_a:
       your_function1()
   else:
       your_function2()

...

def your_function2():
   if condition_b:
       # do something
       # and then exit the outer if block
   else:
       # more code here

回答 8

还有另一种方法不依赖于定义函数(因为有时对于小的代码片段而言,其可读性较低),不使用额外的外部while循环(可能需要对注释进行特殊理解,以便乍一看也可以理解) ,不使用goto(…),最重要的是,如果不需要,则让您保持外部的缩进级别。

if some_condition:
   ...
   if condition_a:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if: # if and only if exit_if wasn't set we want to execute the following code
   # keep doing something
   if condition_b:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if:
   # keep doing something

是的,这还需要重新审视其可读性,但是,如果代码段很小,则不需要跟踪任何永远不会重复的while循环,并且在了解了中间if的含义之后,它很容易阅读,所有内容一个位置并具有相同的缩进。

而且它应该非常有效。

There is another way which doesn’t rely on defining functions (because sometimes that’s less readable for small code snippets), doesn’t use an extra outer while loop (which might need special appreciation in the comments to even be understandable on first sight), doesn’t use goto (…) and most importantly let’s you keep your indentation level for the outer if so you don’t have to start nesting stuff.

if some_condition:
   ...
   if condition_a:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if: # if and only if exit_if wasn't set we want to execute the following code
   # keep doing something
   if condition_b:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if:
   # keep doing something

Yes, that also needs a second look for readability, however, if the snippets of code are small this doesn’t require to track any while loops that will never repeat and after understanding what the intermediate ifs are for, it’s easily readable, all in one place and with the same indentation.

And it should be pretty efficient.


回答 9

所以在这里我了解到您正在尝试突破外部if代码块

if some_condition:
    ...
    if condition_a:
       # do something
       # and then exit the outer if block
       ...
    if condition_b:
       # do something
       # and then exit the outer if block
# more code here

一种解决方法是,您可以在外部if块中测试是否存在错误条件,然后隐式退出代码块,然后使用else块嵌套其他ifs以执行某些操作

if test_for_false:
    # Exit the code(which is the outer if code)

else:
    if condition_a:
        # Do something

    if condition_b:
        # Do something

So here i understand you’re trying to break out of the outer if code block

if some_condition:
    ...
    if condition_a:
       # do something
       # and then exit the outer if block
       ...
    if condition_b:
       # do something
       # and then exit the outer if block
# more code here

One way out of this is that you can test for for a false condition in the outer if block, which will then implicitly exit out of the code block, you then use an else block to nest the other ifs to do something

if test_for_false:
    # Exit the code(which is the outer if code)

else:
    if condition_a:
        # Do something

    if condition_b:
        # Do something

回答 10

无需其他方法即可应用此功能的唯一elif示例是以下示例

a = ['yearly', 'monthly', 'quartly', 'semiannual', 'monthly', 'quartly', 'semiannual', 'yearly']
# start the condition
if 'monthly' in b: 
    print('monthly') 
elif 'quartly' in b: 
    print('quartly') 
elif 'semiannual' in b: 
    print('semiannual') 
elif 'yearly' in b: 
    print('yearly') 
else: 
    print('final') 

The only thing that would apply this without additional methods is elif as the following example

a = ['yearly', 'monthly', 'quartly', 'semiannual', 'monthly', 'quartly', 'semiannual', 'yearly']
# start the condition
if 'monthly' in b: 
    print('monthly') 
elif 'quartly' in b: 
    print('quartly') 
elif 'semiannual' in b: 
    print('semiannual') 
elif 'yearly' in b: 
    print('yearly') 
else: 
    print('final') 

回答 11

这是处理此问题的另一种方法。它使用单个项目进行循环,使您可以仅使用continue。它避免了不必要的不​​必要的额外功能。并且另外消除了潜在的无限while循环。

if something:
    for _ in [0]:
        # Get x
        if not x:
            continue

        # Get y
        if not y:
            continue

        # Get z
        if not z:
            continue

        # Stuff that depends on x, y, and z

Here’s another way to handle this. It uses a single item for loop that enables you to just use continue. It prevents the unnecessary need to have extra functions for no reason. And additionally eliminates potential infinite while loops.

if something:
    for _ in [0]:
        # Get x
        if not x:
            continue

        # Get y
        if not y:
            continue

        # Get z
        if not z:
            continue

        # Stuff that depends on x, y, and z

回答 12

使用return中,如果条件将回报您从功能出来,这样就可以使用回打破的,如果条件。

use return in the if condition will returns you out from the function, so that you can use return to break the the if condition.


如何摆脱多重循环?

问题:如何摆脱多重循环?

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

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?


回答 0

我的第一个直觉是将嵌套循环重构为一个函数,然后使用它return来分解。

My first instinct would be to refactor the nested loop into a function and use return to break out.


回答 1

这是另一种简短的方法。缺点是您只能打破外部循环,但是有时正是您想要的。

for a in xrange(10):
    for b in xrange(20):
        if something(a, b):
            # Break the inner loop...
            break
    else:
        # Continue if the inner loop wasn't broken.
        continue
    # Inner loop was broken, break the outer.
    break

这使用了for / else构造,其解释如下:为什么python在for和while循环之后为什么使用’else’?

关键见解:似乎外部循环总是在中断。但是,如果内部循环不中断,那么外部循环也不会。

continue句话是魔术。在for-else子句中。根据定义,如果没有内部中断,则会发生这种情况。在这种情况下,可以continue巧妙地规避外部中断。

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.

for a in xrange(10):
    for b in xrange(20):
        if something(a, b):
            # Break the inner loop...
            break
    else:
        # Continue if the inner loop wasn't broken.
        continue
    # Inner loop was broken, break the outer.
    break

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 situation continue neatly circumvents the outer break.


回答 2

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.


回答 3

首先,普通逻辑是有帮助的。

如果由于某种原因无法确定终止条件,则exceptions是后备计划。

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

对于此特定示例,可能不需要exceptions。

另一方面,在字符模式应用程序中,我们经常有“ Y”,“ N”和“ Q”选项。对于“ Q”选项,我们希望立即退出。那更exceptions。

First, ordinary logic is helpful.

If, for some reason, the terminating conditions can’t be worked out, exceptions are a fall-back plan.

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

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.


回答 4

我倾向于同意重构为函数通常是解决这种情况的最佳方法,但是对于确实需要打破嵌套循环的情况,这是@ S.Lott描述的异常引发方法的一个有趣变体。它使用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)Exception每次使用都会获得一个定制的子类nested_break;无需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:

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

Now you can use this context manager as follows:

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"

Advantages: (1) it’s slightly cleaner (no explicit try-except block), and (2) you get a custom-built Exception subclass for each use of nested_break; no need to declare your own Exception subclass each time.


回答 5

首先,您还可以考虑使获取和验证输入的过程成为一个函数。在该函数中,您可以只返回正确的值,否则返回while循环。这从根本上消除了您解决的问题,通常可以在更一般的情况下使用(突破多个循环)。如果您绝对必须在您的代码中保留此结构,并且真的不想处理簿记布尔值…

您还可以按以下方式使用goto(从此处使用April Fools模块):

#import the stuff
from goto import goto, label

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": goto .breakall
        if ok == "n" or ok == "N": break
    #do more processing with menus and stuff
label .breakall

我知道,我知道“您不应该使用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):

#import the stuff
from goto import goto, label

while True:
    #snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": goto .breakall
        if ok == "n" or ok == "N": break
    #do more processing with menus and stuff
label .breakall

I know, I know, “thou shalt not use goto” and all that, but it works well in strange cases like this.


回答 6

引入一个新变量,将其用作“循环断路器”。首先给它分配一些东西(False,0,等等),然后在外循环内部,从它断开之前,将值更改为其他东西(True,1,…)。一旦循环退出,请在“父”循环中检查该值。让我示范一下:

breaker = False #our mighty loop exiter!
while True:
    while True:
        if conditionMet:
            #insert code here...
            breaker = True 
            break
    if breaker: # the interesting part!
        break   # <--- !

如果您有无限循环,这是唯一的出路。对于其他循环,执行速度实际上要快得多。如果您有许多嵌套循环,这也适用。您可以全部退出,也可以退出几个。无限可能!希望这对您有所帮助!

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:

breaker = False #our mighty loop exiter!
while True:
    while True:
        if conditionMet:
            #insert code here...
            breaker = True 
            break
    if breaker: # the interesting part!
        break   # <--- !

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!


回答 7

要打破多个嵌套循环而不重构为函数,请使用带有内置StopIteration异常的“模拟goto语句” :

try:
    for outer in range(100):
        for inner in range(100):
            if break_early():
                raise StopIteration

except StopIteration: pass

这个讨论关于使用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:

try:
    for outer in range(100):
        for inner in range(100):
            if break_early():
                raise StopIteration

except StopIteration: pass

See this discussion on the use of goto statements for breaking out of nested loops.


回答 8


keeplooping=True
while keeplooping:
    #Do Stuff
    while keeplooping:
          #do some other stuff
          if finisheddoingstuff(): keeplooping=False

或类似的东西。您可以在内部循环中设置一个变量,并在内部循环退出后立即在外部循环中检查它,如果合适的话,可以中断。我有点像GOTO方法,但前提是您不介意使用愚人节的笑话模块-它不是Python语言的,但确实有道理。


keeplooping=True
while keeplooping:
    #Do Stuff
    while keeplooping:
          #do some other stuff
          if finisheddoingstuff(): keeplooping=False

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 kinda like the GOTO method, provided you don’t mind using an April Fool’s joke module – its not Pythonic, but it does make sense.


回答 9

这不是最漂亮的方法,但是我认为这是最好的方法。

def loop():
    while True:
    #snip: print out current state
        while True:
            ok = get_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": return
            if ok == "n" or ok == "N": break
        #do more processing with menus and stuff

我很确定您也可以在这里使用递归来解决问题,但是我不知道这是否对您来说是个好选择。

This isn’t the prettiest way to do it, but in my opinion, it’s the best way.

def loop():
    while True:
    #snip: print out current state
        while True:
            ok = get_input("Is this ok? (y/n)")
            if ok == "y" or ok == "Y": return
            if ok == "n" or ok == "N": break
        #do more processing with menus and stuff

I’m pretty sure you could work out something using recursion here as well, but I dunno if that’s a good option for you.


回答 10

如果两个条件都成立,为什么不继续循环呢?我认为这是一种更Python化的方式:

dejaVu = True

while dejaVu:
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y" or ok == "n" or ok == "N":
            dejaVu = False
            break

是不是

祝一切顺利。

And why not to keep looping if two conditions are true? I think this is a more pythonic way:

dejaVu = True

while dejaVu:
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y" or ok == "n" or ok == "N":
            dejaVu = False
            break

Isn’t it?

All the best.


回答 11

将循环逻辑分解为一个迭代器,该迭代器产生循环变量并在完成后返回-这是一个简单的示例,它以行/列的形式排列图像,直到我们没有图像或放置位置为止:

def it(rows, cols, images):
    i = 0
    for r in xrange(rows):
        for c in xrange(cols):
            if i >= len(images):
                return
            yield r, c, images[i]
            i += 1 

for r, c, image in it(rows=4, cols=4, images=['a.jpg', 'b.jpg', 'c.jpg']):
    ... do something with r, c, image ...

这具有拆分复杂的循环逻辑和处理的优点。

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:

def it(rows, cols, images):
    i = 0
    for r in xrange(rows):
        for c in xrange(cols):
            if i >= len(images):
                return
            yield r, c, images[i]
            i += 1 

for r, c, image in it(rows=4, cols=4, images=['a.jpg', 'b.jpg', 'c.jpg']):
    ... do something with r, c, image ...

This has the advantage of splitting up the complicated loop logic and the processing…


回答 12

在这种情况下,正如其他人指出的那样,功能分解也是解决之道。Python 3中的代码:

def user_confirms():
    while True:
        answer = input("Is this OK? (y/n) ").strip().lower()
        if answer in "yn":
            return answer == "y"

def main():
    while True:
        # do stuff
        if user_confirms():
            break

In this case, as pointed out by others as well, functional decomposition is the way to go. Code in Python 3:

def user_confirms():
    while True:
        answer = input("Is this OK? (y/n) ").strip().lower()
        if answer in "yn":
            return answer == "y"

def main():
    while True:
        # do stuff
        if user_confirms():
            break

回答 13

Python while ... else结构中有一个隐藏的技巧,可用于模拟两次中断,而无需进行大量代码更改/添加。本质上,如果while条件为假,else则触发该块。既不exceptions,continue也不break触发该else块。有关更多信息,请参见“ Python while语句上的Else子句 ”或while(v2.7)上的Python文档的答案。

while True:
    #snip: print out current state
    ok = ""
    while ok != "y" and ok != "n":
        ok = get_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N":
            break    # Breaks out of inner loop, skipping else

    else:
        break        # Breaks out of outer loop

    #do more processing with menus and stuff

唯一的缺点是您需要将双破折号条件移入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 the while condition is false, the else block is triggered. Neither exceptions, continue or break trigger the else block. For more information see answers to “Else clause on Python while statement“, or Python doc on while (v2.7).

while True:
    #snip: print out current state
    ok = ""
    while ok != "y" and ok != "n":
        ok = get_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N":
            break    # Breaks out of inner loop, skipping else

    else:
        break        # Breaks out of outer loop

    #do more processing with menus and stuff

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 the for loop, where the else block is triggered after loop completion.


回答 14

将迭代减少到单级循环的另一种方法是通过使用python参考中也指定的生成器

for i, j in ((i, j) for i in A for j in B):
    print(i , j)
    if (some_condition):
        break

您可以将其扩展到循环的任意数量的级别

缺点是您不能再只打破一个级别。全部或全无。

另一个缺点是它不适用于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

for i, j in ((i, j) for i in A for j in B):
    print(i , j)
    if (some_condition):
        break

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


回答 15

我来这里的原因是我有一个外部循环和一个内部循环,如下所示:

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的特定情况,但我希望将其发布,以帮助某人以不同的方式思考他们的问题,同时保持简单。

My reason for coming here is that i had an outer loop and an inner loop like so:

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

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:

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

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.


回答 16

尝试使用无限生成器。

from itertools import repeat
inputs = (get_input("Is this ok? (y/n)") for _ in repeat(None))
response = (i.lower()=="y" for i in inputs if i.lower() in ("y", "n"))

while True:
    #snip: print out current state
    if next(response):
        break
    #do more processing with menus and stuff

Try using an infinite generator.

from itertools import repeat
inputs = (get_input("Is this ok? (y/n)") for _ in repeat(None))
response = (i.lower()=="y" for i in inputs if i.lower() in ("y", "n"))

while True:
    #snip: print out current state
    if next(response):
        break
    #do more processing with menus and stuff

回答 17

通过使用一个函数:

def myloop():
    for i in range(1,6,1):  # 1st loop
        print('i:',i)
        for j in range(1,11,2):  # 2nd loop
            print('   i, j:' ,i, j)
            for k in range(1,21,4):  # 3rd loop
                print('      i,j,k:', i,j,k)
                if i%3==0 and j%3==0 and k%3==0:
                    return  # getting out of all loops

myloop()

尝试通过注释掉来运行上面的代码return

不使用任何功能:

done = False
for i in range(1,6,1):  # 1st loop
    print('i:', i)
    for j in range(1,11,2):  # 2nd loop
        print('   i, j:' ,i, j)
        for k in range(1,21,4):  # 3rd loop
            print('      i,j,k:', i,j,k)
            if i%3==0 and j%3==0 and k%3==0:
                done = True
                break  # breaking from 3rd loop
        if done: break # breaking from 2nd loop
    if done: break     # breaking from 1st loop

现在,按原样运行上面的代码,然后尝试通过break从底部开始注释掉包含一行的每一行来运行。

By using a function:

def myloop():
    for i in range(1,6,1):  # 1st loop
        print('i:',i)
        for j in range(1,11,2):  # 2nd loop
            print('   i, j:' ,i, j)
            for k in range(1,21,4):  # 3rd loop
                print('      i,j,k:', i,j,k)
                if i%3==0 and j%3==0 and k%3==0:
                    return  # getting out of all loops

myloop()

Try running the above codes by commenting out the return as well.

Without using any function:

done = False
for i in range(1,6,1):  # 1st loop
    print('i:', i)
    for j in range(1,11,2):  # 2nd loop
        print('   i, j:' ,i, j)
        for k in range(1,21,4):  # 3rd loop
            print('      i,j,k:', i,j,k)
            if i%3==0 and j%3==0 and k%3==0:
                done = True
                break  # breaking from 3rd loop
        if done: break # breaking from 2nd loop
    if done: break     # breaking from 1st loop

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.


回答 18

将多个循环转换为单个可中断循环的一种简单方法是使用 numpy.ndindex

for i in range(n):
  for j in range(n):
    val = x[i, j]
    break # still inside the outer loop!

for i, j in np.ndindex(n, n):
  val = x[i, j]
  break # you left the only loop there was!

您确实必须索引到您的对象中,而不是能够显式地遍历值,但是至少在简单的情况下,它似乎比大多数建议的答案简单约2至20倍。

An easy way to turn multiple loops into a single, breakable loop is to use numpy.ndindex

for i in range(n):
  for j in range(n):
    val = x[i, j]
    break # still inside the outer loop!

for i, j in np.ndindex(n, n):
  val = x[i, j]
  break # you left the only loop there was!

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.


回答 19

# this version uses a level counter to choose how far to break out

break_levels = 0
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_levels = 1        # how far nested, excluding this break
            break
        if ok == "n" or ok == "N":
            break                   # normal break
    if break_levels:
        break_levels -= 1
        break                       # pop another level
if break_levels:
    break_levels -= 1
    break

# ...and so on
# this version uses a level counter to choose how far to break out

break_levels = 0
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_levels = 1        # how far nested, excluding this break
            break
        if ok == "n" or ok == "N":
            break                   # normal break
    if break_levels:
        break_levels -= 1
        break                       # pop another level
if break_levels:
    break_levels -= 1
    break

# ...and so on

回答 20

如果不喜欢将其重构为函数,可能会出现如下所示的小技巧

添加了1个break_level变量来控制while循环条件

break_level = 0
# while break_level < 3: # if we have another level of nested loop here
while break_level < 2:
    #snip: print out current state
    while break_level < 1:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": break_level = 2 # break 2 level
        if ok == "n" or ok == "N": break_level = 1 # break 1 level

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_level = 0
# while break_level < 3: # if we have another level of nested loop here
while break_level < 2:
    #snip: print out current state
    while break_level < 1:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y": break_level = 2 # break 2 level
        if ok == "n" or ok == "N": break_level = 1 # break 1 level

回答 21

您可以定义一个变量(例如break_statement),然后在发生两次中断条件时将其更改为另一个值,并在if语句中使用它来从第二个循环中断。

while True:
    break_statement=0
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N": 
            break
        if ok == "y" or ok == "Y": 
            break_statement=1
            break
    if break_statement==1:
        break

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.

while True:
    break_statement=0
    while True:
        ok = raw_input("Is this ok? (y/n)")
        if ok == "n" or ok == "N": 
            break
        if ok == "y" or ok == "Y": 
            break_statement=1
            break
    if break_statement==1:
        break

回答 22

我想提醒您,Python中的函数可以在代码中间创建,并且可以透明地访问周围的变量以进行读取以及使用with nonlocalglobal声明进行写入。

因此,您可以将函数用作“易碎控件结构”,从而定义要返回的位置:

def is_prime(number):

    foo = bar = number

    def return_here():
        nonlocal foo, bar
        init_bar = bar
        while foo > 0:
            bar = init_bar
            while bar >= foo:
                if foo*bar == number:
                    return
                bar -= 1
            foo -= 1

    return_here()

    if foo == 1:
        print(number, 'is prime')
    else:
        print(number, '=', bar, '*', foo)

>>> is_prime(67)
67 is prime
>>> is_prime(117)
117 = 13 * 9
>>> is_prime(16)
16 = 4 * 4

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 or global declaration for writing.

So you can use a function as a “breakable control structure”, defining a place you want to return to:

def is_prime(number):

    foo = bar = number

    def return_here():
        nonlocal foo, bar
        init_bar = bar
        while foo > 0:
            bar = init_bar
            while bar >= foo:
                if foo*bar == number:
                    return
                bar -= 1
            foo -= 1

    return_here()

    if foo == 1:
        print(number, 'is prime')
    else:
        print(number, '=', bar, '*', foo)

>>> is_prime(67)
67 is prime
>>> is_prime(117)
117 = 13 * 9
>>> is_prime(16)
16 = 4 * 4

回答 23

两种解决方案

举一个例子:这两个矩阵相等/相同吗?
matrix1和matrix2的大小相同,分别是n,2个二维矩阵。

第一个解决方案没有一个功能

same_matrices = True
inner_loop_broken_once = False
n = len(matrix1)

for i in range(n):
    for j in range(n):

        if matrix1[i][j] != matrix2[i][j]:
            same_matrices = False
            inner_loop_broken_once = True
            break

    if inner_loop_broken_once:
        break

第二个解决方案带有功能
这是我的案例的最终解决方案

def are_two_matrices_the_same (matrix1, matrix2):
    n = len(matrix1)
    for i in range(n):
        for j in range(n):
            if matrix1[i][j] != matrix2[i][j]:
                return False
    return True

祝你今天愉快!

Solutions in 2 Ways

With an example: Are these two matrices equal/same?
matrix1 and matrix2 are same size, n, 2 dimentional matrices.

First Solution, without a function

same_matrices = True
inner_loop_broken_once = False
n = len(matrix1)

for i in range(n):
    for j in range(n):

        if matrix1[i][j] != matrix2[i][j]:
            same_matrices = False
            inner_loop_broken_once = True
            break

    if inner_loop_broken_once:
        break

Second Solution, with a function
This is the final solution for my case

def are_two_matrices_the_same (matrix1, matrix2):
    n = len(matrix1)
    for i in range(n):
        for j in range(n):
            if matrix1[i][j] != matrix2[i][j]:
                return False
    return True

Have a nice day!


回答 24

# this version breaks up to a certain label

break_label = None
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_label = "outer"   # specify label to break to
            break
        if ok == "n" or ok == "N":
            break
    if break_label:
        if break_label != "inner":
            break                   # propagate up
        break_label = None          # we have arrived!
if break_label:
    if break_label != "outer":
        break                       # propagate up
    break_label = None              # we have arrived!

#do more processing with menus and stuff
# this version breaks up to a certain label

break_label = None
while True:
    # snip: print out current state
    while True:
        ok = get_input("Is this ok? (y/n)")
        if ok == "y" or ok == "Y":
            break_label = "outer"   # specify label to break to
            break
        if ok == "n" or ok == "N":
            break
    if break_label:
        if break_label != "inner":
            break                   # propagate up
        break_label = None          # we have arrived!
if break_label:
    if break_label != "outer":
        break                       # propagate up
    break_label = None              # we have arrived!

#do more processing with menus and stuff

回答 25

希望这会有所帮助:

x = True
y = True
while x == True:
    while y == True:
         ok = get_input("Is this ok? (y/n)") 
         if ok == "y" or ok == "Y":
             x,y = False,False #breaks from both loops
         if ok == "n" or ok == "N": 
             break #breaks from just one

Hopefully this helps:

x = True
y = True
while x == True:
    while y == True:
         ok = get_input("Is this ok? (y/n)") 
         if ok == "y" or ok == "Y":
             x,y = False,False #breaks from both loops
         if ok == "n" or ok == "N": 
             break #breaks from just one

回答 26

这是一个似乎可行的实现:

break_ = False
for i in range(10):
    if break_:
        break
    for j in range(10):
        if j == 3:
            break_ = True
            break
        else:
            print(i, j)

唯一的缺点是您必须break_在循环之前定义。

Here’s an implementation that seems to work:

break_ = False
for i in range(10):
    if break_:
        break
    for j in range(10):
        if j == 3:
            break_ = True
            break
        else:
            print(i, j)

The only draw back is that you have to define break_ before the loops.


回答 27

从语言层面上无法做到这一点。有些语言可以跳转,而其他语言则需要带参数,而python则不需要。

最好的选择是:

  1. 设置一个由外循环检查的标志,或设置外循环条件。

  2. 将循环放入函数中,然后使用return一次退出所有循环。

  3. 重新制定您的逻辑。

自1987年以来担任程序员的Vivek Nagarajan


使用功能

def doMywork(data):
    for i in data:
       for e in i:
         return 

使用标志

is_break = False
for i in data:
   if is_break:
      break # outer loop break
   for e in i:
      is_break = True
      break # inner loop break

There is no way to do this from a language level. Some languages have a goto others have a break that takes an argument, python does not.

The best options are:

  1. Set a flag which is checked by the outer loop, or set the outer loops condition.

  2. Put the loop in a function and use return to break out of all the loops at once.

  3. Reformulate your logic.

Credit goes to Vivek Nagarajan, Programmer since 1987


Using Function

def doMywork(data):
    for i in data:
       for e in i:
         return 

Using flag

is_break = False
for i in data:
   if is_break:
      break # outer loop break
   for e in i:
      is_break = True
      break # inner loop break

回答 28

与之前的相似,但更紧凑。(布尔只是数字)

breaker = False #our mighty loop exiter!
while True:
    while True:
        ok = get_input("Is this ok? (y/n)")
        breaker+= (ok.lower() == "y")
        break

    if breaker: # the interesting part!
        break   # <--- !

Similar like the one before, but more compact. (Booleans are just numbers)

breaker = False #our mighty loop exiter!
while True:
    while True:
        ok = get_input("Is this ok? (y/n)")
        breaker+= (ok.lower() == "y")
        break

    if breaker: # the interesting part!
        break   # <--- !

回答 29

由于此问题已成为进入特定循环的标准问题,因此我想用给出示例Exception

尽管在多重循环结构中没有名为“循环中断”的标签,但是我们可以利用用户定义的异常来进入我们选择的特定循环。考虑下面的示例,在该示例中,我们将在base-6编号系统中打印最多4位数字的所有数字:

class BreakLoop(Exception):
    def __init__(self, counter):
        Exception.__init__(self, 'Exception 1')
        self.counter = counter

for counter1 in range(6):   # Make it 1000
    try:
        thousand = counter1 * 1000
        for counter2 in range(6):  # Make it 100
            try:
                hundred = counter2 * 100
                for counter3 in range(6): # Make it 10
                    try:
                        ten = counter3 * 10
                        for counter4 in range(6):
                            try:
                                unit = counter4
                                value = thousand + hundred + ten + unit
                                if unit == 4 :
                                    raise BreakLoop(4) # Don't break from loop
                                if ten == 30: 
                                    raise BreakLoop(3) # Break into loop 3
                                if hundred == 500:
                                    raise BreakLoop(2) # Break into loop 2
                                if thousand == 2000:
                                    raise BreakLoop(1) # Break into loop 1

                                print('{:04d}'.format(value))
                            except BreakLoop as bl:
                                if bl.counter != 4:
                                    raise bl
                    except BreakLoop as bl:
                        if bl.counter != 3:
                            raise bl
            except BreakLoop as bl:
                if bl.counter != 2:
                    raise bl
    except BreakLoop as bl:
        pass

当我们打印输出时,我们将永远不会得到单位位置为4的任何值。在那种情况下,我们不会像BreakLoop(4)引发和陷入同一循环那样从任何循环中中断。同样,只要十位有3,我们就会使用进入第三循环BreakLoop(3)。每当百位有5时,我们就使用进入第二个循环BreakLoop(2),每千位有2时,我们使用进入第一个循环BreakLoop(1)

简而言之,在内部循环中引发Exception(内置的或用户定义的),然后将其捕获到要从中恢复控制的循环中。如果要中断所有循环,请在所有循环之外捕获Exception。(我没有在示例中显示这种情况)。

Since this question has become a standard question for breaking into a particular loop, I would like to give my answer with example using Exception.

Although there exists no label named breaking of loop in multipally looped construct, we can make use of User-defined Exceptions to break into a particular loop of our choice. Consider the following example where let us print all numbers upto 4 digits in base-6 numbering system:

class BreakLoop(Exception):
    def __init__(self, counter):
        Exception.__init__(self, 'Exception 1')
        self.counter = counter

for counter1 in range(6):   # Make it 1000
    try:
        thousand = counter1 * 1000
        for counter2 in range(6):  # Make it 100
            try:
                hundred = counter2 * 100
                for counter3 in range(6): # Make it 10
                    try:
                        ten = counter3 * 10
                        for counter4 in range(6):
                            try:
                                unit = counter4
                                value = thousand + hundred + ten + unit
                                if unit == 4 :
                                    raise BreakLoop(4) # Don't break from loop
                                if ten == 30: 
                                    raise BreakLoop(3) # Break into loop 3
                                if hundred == 500:
                                    raise BreakLoop(2) # Break into loop 2
                                if thousand == 2000:
                                    raise BreakLoop(1) # Break into loop 1

                                print('{:04d}'.format(value))
                            except BreakLoop as bl:
                                if bl.counter != 4:
                                    raise bl
                    except BreakLoop as bl:
                        if bl.counter != 3:
                            raise bl
            except BreakLoop as bl:
                if bl.counter != 2:
                    raise bl
    except BreakLoop as bl:
        pass

When we print the output, we will never get any value whose unit place is with 4. In that case, we don’t break from any loop as BreakLoop(4) is raised and caught in same loop. Similarly, whenever ten place is having 3, we break into third loop using BreakLoop(3). Whenever hundred place is having 5, we break into second loop using BreakLoop(2) and whenver the thousand place is having 2, we break into first loop using BreakLoop(1).

In short, raise your Exception (in-built or user defined) in the inner loops, and catch it in the loop from where you want to resume your control to. If you want to break from all loops, catch the Exception outside all the loops. (I have not shown this case in example).