Usage of break statement in Python [duplicate] - python

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?

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

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.

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.

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.

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!

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.

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.

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.

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 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.
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 don't know if that's a good option for you.

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

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:
Set a flag which is checked by the outer loop, or set the outer
loops condition.
Put the loop in a function and use return to break out of all the loops at once.
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

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...

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.

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.

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

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

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

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.

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

# 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 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

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.

What I would personally do is use a boolean that toggles when I am ready to break out the outer loop. For example
while True:
#snip: print out current state
quit = False
while True:
ok = input("Is this ok? (y/n)")
if ok.lower() == "y":
quit = True
break # this should work now :-)
if ok.lower() == "n":
quit = True
break # This should work too :-)
if quit:
break
#do more processing with menus and stuff

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

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

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

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.

Trying to minimal changes to the OP's question, I just added a flag before breaking the 1st for loop and check that flag on the outer loop to see if we need to brake once again.
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

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:
b = None
for a in range(10):
if something(a, b): # should never = True if b is None
break
for b in range(20):
pass
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.

Related

how to exit from set of loops at once and going back to the first loop? [duplicate]

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?
My first instinct would be to refactor the nested loop into a function and use return to break out.
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.
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.
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.
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!
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.
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.
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.
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 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.
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 don't know if that's a good option for you.
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
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:
Set a flag which is checked by the outer loop, or set the outer
loops condition.
Put the loop in a function and use return to break out of all the loops at once.
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
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...
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.
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.
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
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
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
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.
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
# 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 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
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.
What I would personally do is use a boolean that toggles when I am ready to break out the outer loop. For example
while True:
#snip: print out current state
quit = False
while True:
ok = input("Is this ok? (y/n)")
if ok.lower() == "y":
quit = True
break # this should work now :-)
if ok.lower() == "n":
quit = True
break # This should work too :-)
if quit:
break
#do more processing with menus and stuff
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
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
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
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
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.
Trying to minimal changes to the OP's question, I just added a flag before breaking the 1st for loop and check that flag on the outer loop to see if we need to brake once again.
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
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:
b = None
for a in range(10):
if something(a, b): # should never = True if b is None
break
for b in range(20):
pass
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.

Break out of while True loop with function

So I have a while true loop -
while True:
getStatus()
print('Ended')
I hope to be able to break out of it if answer is 999. this is what I tried:
def getStatus():
answer = input('What is the box ID? ')
if answer == 999:
return False
elif type(answer) == int:
boxId = answer + 1
print(boxId)
However even when the input is '999' it loops back and asks 'What is the box ID? ' again.
How do I get out of the while true loop?
Your while loop keeps looping because that's exactly what you've told it to do. After the function you call from its body returns, you ignore the return value, unconditionally print "Ended" and then do it all again, since the condition on the loop is obviously still truthy.
If you want the function to control if the loop keeps going, you should use its return value as the condition in the loop, with something like this:
running = True
while running:
running = getStatus()
print("Ended") # move this outside the loop!
This requires that getStatus returns a truthy value when you want to keep looping and a falsey value when you want to stop. Your current implementation of that function doesn't do that. It returns False when 999 is entered, but doesn't explicitly return anything if you give other input (which in Python is equivalent to returning None). Since both False and None are falsey, the code above won't actually work (you could patch it with something like running = getStatus() is None, but that would be horrible). You should change the function to have an explicit return statement in all of its branches (including the case for non-integer inputs, where it doesn't go into either your if or elif blocks).
If the loop and the function's logic are tightly intertwined, it might make sense to move the loop into the function itself, rather than having it be separate and needing to use a return value to signal when to stop. In a single function, you can use break to exit a loop directly:
def getStatus():
while True:
answer = input('What is the box ID? ')
if answer == 999:
break
elif isinstance(answer, int): # isinsance() is better than type(...) == ...
boxId = answer + 1
print(boxId)
else:
print("I'm sorry, I didn't understand that.") # still good to handle this case
you can add if statement before get_status() that will check if it's true and break and in the get_status function you will have to return true to break
def getStatus():
answer = input('What is the box ID? ')
if answer == 999:
return True
elif type(answer) == int:
boxId = answer + 1
print(boxId)
while True:
if getStatus():
print('Ended')
break
def selectedCountry():
while True:
country = input("Enter country of which you want to check pictures HR, RS, RO: ").upper()
if country == str("HR") or country == str("RO") or country == str("RS"):
break
else:
print("Please enter HR or RO or RS: " + "you wrote: " + country)
Why while True is working outside of a function and inside the same problem with asking again
Enter country of which you want to check pictures HR, RS, RO: >? hr
Enter country of which you want to check pictures HR, RS, RO:
You may change it to -
while True:
if(getStatus()==False):
print('Ended')
break
By this you can use returned value to break out of infinite loop.

Handling nested loops cleanly in Python [duplicate]

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?
My first instinct would be to refactor the nested loop into a function and use return to break out.
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.
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.
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.
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!
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.
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.
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.
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 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.
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 don't know if that's a good option for you.
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
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:
Set a flag which is checked by the outer loop, or set the outer
loops condition.
Put the loop in a function and use return to break out of all the loops at once.
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
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...
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.
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.
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
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
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
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.
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
# 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 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
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.
What I would personally do is use a boolean that toggles when I am ready to break out the outer loop. For example
while True:
#snip: print out current state
quit = False
while True:
ok = input("Is this ok? (y/n)")
if ok.lower() == "y":
quit = True
break # this should work now :-)
if ok.lower() == "n":
quit = True
break # This should work too :-)
if quit:
break
#do more processing with menus and stuff
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
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
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
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
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.
Trying to minimal changes to the OP's question, I just added a flag before breaking the 1st for loop and check that flag on the outer loop to see if we need to brake once again.
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
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:
b = None
for a in range(10):
if something(a, b): # should never = True if b is None
break
for b in range(20):
pass
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.

Break out of a while loop using a function

Is there any way to break out of infinite loops using functions? E.g.,
# Python 3.3.2
yes = 'y', 'Y'
no = 'n', 'N'
def example():
if egg.startswith(no):
break
elif egg.startswith(yes):
# Nothing here, block may loop again
print()
while True:
egg = input("Do you want to continue? y/n")
example()
This causes the following error:
SyntaxError: 'break' outside loop
Please explain why this is happening and how this can be fixed.
As far as I'm concerned you cannot call break from within example() but you can make it to return a value(eg : A boolean) in order to stop the infinite loop
The code:
yes='y', 'Y'
no='n', 'N'
def example():
if egg.startswith(no):
return False # Returns False if egg is either n or N so the loop would break
elif egg.startswith(yes):
# Nothing here, block may loop again
print()
return True # Returns True if egg is either y or Y so the loop would continue
while True:
egg = input("Do you want to continue? y/n")
if not example(): # You can aslo use "if example() == False:" Though it is not recommended!
break
The way to end a while-true loop would be to use break. Furthermore, the break must be in the immediate scope of the loop. Otherwise, you could utilize exceptions to hand control up in the stack to whatever code handles it.
Yet, oftentimes it's worth considering another approach. If your example is actually close to what you really want to do, namely depending on some user prompt input, I'd do it like this:
if raw_input('Continue? y/n') == 'y':
print 'You wish to continue then.'
else:
print 'Abort, as you wished.'
An alternative way to break out of a function inside of a loop would be to raise StopIteration from within the function, and to except StopIteration outside of the loop. This will cause the loop to stop immediately. E.g.,
yes = ('y', 'Y')
no = ('n', 'N')
def example():
if egg.startswith(no):
# Break out of loop.
raise StopIteration()
elif egg.startswith(yes):
# Nothing here, block may loop again.
print()
try:
while True:
egg = input("Do you want to continue? y/n")
example()
except StopIteration:
pass

python - check at the end of the loop if need to run again

It's a really basic question but i can't think at the second. How do i set up a loop that asks each time the function inside runs whether to do it again. So it runs it then says something like;
"loop again? y/n"
while True:
func()
answer = raw_input( "Loop again? " )
if answer != 'y':
break
keepLooping = True
while keepLooping:
# do stuff here
# Prompt the user to continue
q = raw_input("Keep looping? [yn]: ")
if not q.startswith("y"):
keepLooping = False
There are two usual approaches, both already mentioned, which amount to:
while True:
do_stuff() # and eventually...
break; # break out of the loop
or
x = True
while x:
do_stuff() # and eventually...
x = False # set x to False to break the loop
Both will work properly. From a "sound design" perspective it's best to use the second method because 1) break can have counterintuitive behavior in nested scopes in some languages; 2) the first approach is counter to the intended use of "while"; 3) your routines should always have a single point of exit
While raw_input("loop again? y/n ") != 'n':
do_stuff()

Categories

Resources