Python: Continuing to next iteration in outer loop

Question:

I wanted to know if there are any built-in ways to continue to next iteration in outer loop in python. For example, consider the code:

for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            continue
    ...block1...

I want this continue statement to exit the jj loop and goto next item in the ii loop. I can implement this logic in some other way (by setting a flag variable), but is there an easy way to do this, or is this like asking for too much?

Asked By: Sahas

||

Answers:

for ii in range(200):
    for jj in range(200, 400):
        ...block0...
        if something:
            break
    else:
        ...block1...

Break will break the inner loop, and block1 won’t be executed (it will run only if the inner loop is exited normally).

Answered By: culebrón

In other languages you can label the loop and break from the labelled loop. Python Enhancement Proposal (PEP) 3136 suggested adding these to Python but Guido rejected it:

However, I’m rejecting it on the basis that code so complicated to
require this feature is very rare. In most cases there are existing
work-arounds that produce clean code, for example using ‘return’.
While I’m sure there are some (rare) real cases where clarity of the
code would suffer from a refactoring that makes it possible to use
return, this is offset by two issues:

  1. The complexity added to the language, permanently. This affects not
    only all Python implementations, but also every source analysis tool,
    plus of course all documentation for the language.

  2. My expectation that the feature will be abused more than it will be
    used right, leading to a net decrease in code clarity (measured across
    all Python code written henceforth). Lazy programmers are everywhere,
    and before you know it you have an incredible mess on your hands of
    unintelligible code.

So if that’s what you were hoping for you’re out of luck, but look at one of the other answers as there are good options there.

Answered By: Dave Webb

I think you could do something like this:

for ii in range(200):
    restart = False
    for jj in range(200, 400):
        ...block0...
        if something:
            restart = True
            break
    if restart:
        continue
    ...block1...
Answered By: asmeurer
for i in ...:
    for j in ...:
        for k in ...:
            if something:
                # continue loop i

In a general case, when you have multiple levels of looping and break does not work for you (because you want to continue one of the upper loops, not the one right above the current one), you can do one of the following

Refactor the loops you want to escape from into a function

def inner():
    for j in ...:
        for k in ...:
            if something:
                return


for i in ...:
    inner()

The disadvantage is that you may need to pass to that new function some variables, which were previously in scope. You can either just pass them as parameters, make them instance variables on an object (create a new object just for this function, if it makes sense), or global variables, singletons, whatever (ehm, ehm).

Or you can define inner as a nested function and let it just capture what it needs (may be slower?)

for i in ...:
    def inner():
        for j in ...:
            for k in ...:
                if something:
                    return
    inner()

Use exceptions

Philosophically, this is what exceptions are for, breaking the program flow through the structured programming building blocks (if, for, while) when necessary.

The advantage is that you don’t have to break the single piece of code into multiple parts. This is good if it is some kind of computation that you are designing while writing it in Python. Introducing abstractions at this early point may slow you down.

Bad thing with this approach is that interpreter/compiler authors usually assume that exceptions are exceptional and optimize for them accordingly.

class ContinueI(Exception):
    pass


continue_i = ContinueI()

for i in ...:
    try:
        for j in ...:
            for k in ...:
                if something:
                    raise continue_i
    except ContinueI:
        continue

Create a special exception class for this, so that you don’t risk accidentally silencing some other exception.

Something else entirely

I am sure there are still other solutions.

Answered By: user7610

Another way to deal with this kind of problem is to use Exception().

for ii in range(200):
    try:
        for jj in range(200, 400):
            ...block0...
            if something:
                raise Exception()
    except Exception:
        continue
    ...block1...

For example:

for n in range(1,4):
    for m in range(1,4):
        print n,'-',m

result:

    1-1
    1-2
    1-3
    2-1
    2-2
    2-3
    3-1
    3-2
    3-3

Assuming we want to jump to the outer n loop from m loop if m =3:

for n in range(1,4):
    try:
        for m in range(1,4):
            if m == 3:
                raise Exception()            
            print n,'-',m
    except Exception:
        continue

result:

    1-1
    1-2
    2-1
    2-2
    3-1
    3-2

Reference link:http://www.programming-idioms.org/idiom/42/continue-outer-loop/1264/python

Answered By: Patrick

We want to find something and then stop the inner iteration. I use a flag system.

for l in f:
    flag = True
    for e in r:
        if flag==False:continue
        if somecondition:
            do_something()
            flag=False
Answered By: Esther

I just did something like this. My solution for this was to replace the interior for loop with a list comprehension.

for ii in range(200):
    done = any([op(ii, jj) for jj in range(200, 400)])
    ...block0...
    if done:
        continue
    ...block1...

where op is some boolean operator acting on a combination of ii and jj. In my case, if any of the operations returned true, I was done.

This is really not that different from breaking the code out into a function, but I thought that using the “any” operator to do a logical OR on a list of booleans and doing the logic all in one line was interesting. It also avoids the function call.

Answered By: cagem12

I think one of the easiest ways to achieve this is to replace “continue” with “break” statement,i.e.

for ii in range(200):
 for jj in range(200, 400):
    ...block0...
    if something:
        break
 ...block1...       

For example, here is the easy code to see how exactly it goes on:

for i in range(10):
    print("doing outer loop")
    print("i=",i)
    for p in range(10):
        print("doing inner loop")
        print("p=",p)
        if p==3:
            print("breaking from inner loop")
            break
    print("doing some code in outer loop")
Answered By: Khelina Fedorchuk

The best approach I know to continue an outer loop is using a Boolean that is scoped under the outer loop and breaking the inner one. Although, depending on the use case you may not break the inner loop, continuing an outer loop inside its inner loop implicitly suggests that you want to immediately jump to the first line of the outer loop and avoid any further execution in the inner one. That is why I added a break statement.

for i in range(0, 6):
    should_continue = False

    for f in range(1, i * 2):
        print(f"f = {f}")
        if (not (f % 1337) or not (f % 7)):
            print(f"{f} can be divided, continue outer loop")
            should_continue = True
            # leaves inner loop
            break

    if(should_continue): continue
    # Outer loop's code goes here
    print(f'Reached outer loopni = {i}')

This approach avoids calling any functions and dealing with possible drawbacks. Calling a function is known to be a rather expensive operation, specially for Games. Now imagine a deeply nested for loop that will run millions of times, wrapping it inside a function won’t result in a smooth experience.

Wrapping the loop inside an exception block is also a bad idea and will be way slower than functions. This is because Python needs a lot of overhead to trigger the exceptions mechanism and later restore the runtime state, exceptions are designed to be used exceptionally. Taking that in mind, even some CPU optimizations such as speculative execution should not be applied to exception blocks and probably aren’t.

The only "problem" I found in this approach is that break will jump once outside of the inner loop, landing on continue, which, in turn, will jump one more time. This, as opposed to a goto statement in C or JavaScript, is a bit more clumsy, but doesn’t have any visible impact in performance, because it would generate only one extra instruction that runs as fast as your CPU’s clock or as the interpreter implementation.

Answered By: Overclocked Skid
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.