36
  for row in b:
    for drug in drug_input:
      for brand in brand_names[drug]:

from the third loop how do i exit the current loop and go to the next value of for row in b: ?

Alex Gordon
  • 57,446
  • 287
  • 670
  • 1,062
  • 1
    I would probably wrap this block in a try and break out of it with a raise. – g.d.d.c Jul 28 '10 at 20:35
  • May I ask what condition in the inner loop would force a `break`? – Caleb Hattingh Jul 28 '10 at 20:43
  • 3
    OK. There are lots of answers here, all of which are correct in that they do indeed break out of two loops. But I don't think you're writing this code right. *Why* are you performing this iteration? Looking back over the last day's worth of posts, I think `b` is a list of rows of a CSV containing some drugs. Why do you need to iterate over every drug you know about, for each row of said CSV? – Katriel Jul 28 '10 at 20:58
  • please expand your example - there are probably better ways to solve it w/o breaking out from outer loop. – Nas Banov Jul 28 '10 at 23:04
  • Python has goto: http://entrian.com/goto/ ;-) (Please do not use this in real code) – Joe D Aug 23 '10 at 20:44
  • why cant i use it in real code – Alex Gordon Aug 23 '10 at 21:21
  • If you read the page linked, then you'll see it was written as an april fools joke. Furthermore it would be considered by most to be bad style and unpythonic. – Joe D Aug 24 '10 at 00:52
  • possible duplicate of [Breaking out of nested loops](http://stackoverflow.com/questions/653509/breaking-out-of-nested-loops) – Lev Levitsky Jan 17 '13 at 21:05

11 Answers11

43

This one uses a boolean to see if you are done yet:

done = False
for x in xs:
    for y in ys:
        if bad:
            done = True
            break

    if done:
        break

This one will continue if no break was used. The else will be skipped over if there was a break, so it will see the next break. This approach has the benefit of not having to use a variable, but may be harder to read to some.

for x in xs:
    for y in ys:
        if bad:
            break
    else:
        continue

    break
Donald Miner
  • 38,889
  • 8
  • 95
  • 118
8
for row in b:
   more_drugs = True
   for drug in drug_input:
      for brand in brand_names[drug]:
          if something:
              more_drugs = False
              break

      if not more_drugs:
          break

Python doesn't have a control structure for breaking from two loops at once, so you need to do something manual like this.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
8

If you have three levels of looping in one method then you probably need to rethink your design.

  • Split your method up into smaller, simpler methods.
  • Use a list comprehension and methods like all and any to avoid writing explicit loops.

Doing either of these should mean that you no longer have this issue.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 1
    I'm not sure I agree with that, specifically in the case of iteration over a complex data structure. Sometimes you just have dictionaries in dictionaries in dictionaries! – Katriel Jul 28 '10 at 20:41
  • @karielalex: You don't agree with the both points, or just the second? – Mark Byers Jul 28 '10 at 20:41
  • With "If you have three levels of looping in one method then you probably need to rethink your design." I think there's a difference between the case of iterating over a data structure -- in which case the multiple iteration is semantically one section and shouldn't necessary be split up or pruned -- and the case where too much is being done in one place. In the latter situation I agree with both your points. For instance, I recently constructed a DFA which had a transition table `initial node` -> `arc type` -> `guard` -> `final node`. To iterate over all edges you need three loops! – Katriel Jul 28 '10 at 20:49
  • Although, reading over this case, I think it's probably an example of the latter. `for row in b` doesn't look promising. – Katriel Jul 28 '10 at 20:53
  • @katrielalex: I agree with you that there are some algorithms where three loops inside each other in a single method makes sense, for example Floyd-Warshall: http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm. I doubt that is the case here, but it's hard to tell from the posted code. I have seen some of the OPs previous questions, so I have a good idea of what the code looks like, and I'm guessing it is not pretty and the highest voted answers are just going to make it even less so. – Mark Byers Jul 28 '10 at 20:54
  • @Mark: How to use methods like all and any to avoid writing explicit loops? – riza Jul 30 '10 at 05:05
7

Exception handling beats setting variables all over the place IMO

for row in b:
    for drug in drug_input:
        try:
            for brand in brand_names[drug]:
                if some_condition:
                    raise StopIteration
        except StopIteration:
            break
brianz
  • 7,268
  • 4
  • 37
  • 44
  • 1
    Exceptions are for exceptional situations only! – Caleb Hattingh Jul 28 '10 at 21:28
  • 1
    "This is derived from Exception rather than StandardError, since this is not considered an error in its normal application." http://docs.python.org/library/exceptions.html#exceptions.StopIteration – brianz Jul 28 '10 at 21:42
  • 1
    Ok, that was a pretty good comeback :) But seriously, don't handle exceptions for control flow. In any language. A try-except handler is a very, very widespread visual cue for "something unusual just happened". – Caleb Hattingh Jul 28 '10 at 21:46
  • 2
    if you are going to use exceptions, why not move the exception handling one level up and not use break? – Muhammad Alkarouri Jul 28 '10 at 21:57
  • @cjrh - Yeah, I mostly agree. I usually don't abuse exceptions like this, but in this case I find it more elegant and this particular exception is designed just for this...to stop iterating. I'd also argue that this is easier to read, and we all know that it counts. :>) – brianz Jul 29 '10 at 00:28
  • I agree with @MuhammadAlkarouri: one level up, and `pass` instead of `break` would be easier to read. Btw, this approach is awesome :) – MestreLion Jun 08 '14 at 11:26
5

I would consider putting the two inner loops in function and using return from there. Probably rethinking what you are doing and how gives the better alternative to that though.

Could you give your current pseudo code, input and output, so we could try to remove the need for the break in first place? We need to see where the loop variables are used or better still, what is the goal of the processing.

Tony Veijalainen
  • 5,447
  • 23
  • 31
5

Latest PEP I see requesting this feature is 3136 (and was rejected): http://mail.python.org/pipermail/python-3000/2007-July/008663.html

Closest & cleanest thing I could see to what you want to do would be do the following (and since even type names are scoped, you could declare LocalBreak within the function its needed):

class LocalBreak(Exception): pass

try:
   for i in ...:
       for h in ...:
           for j in ...:
              if should_break(j):
                 raise LocalBreak()
except LocalBreak:
   pass
Nathan Ernst
  • 4,540
  • 25
  • 38
3
for a in aa:
     for b in bb:
         for c in cc:
            if c == a[b]:
                break
         else:
             continue
         break

Python supports for...else statements. else block is evaluated if the inner break is not fired.

3

If you have too many embedded loops, it might be time for a refactor. In this case, I believe the best refactor is to move your loops into a function and use a return statement. That will force-exit out of any number of loops. For example:

def example(self, drug_input):
    ok = False
    for x in drug_input["names"]:
        for y in range(drug_input["number_of_drugs"]):
            for z in drug_input["list_of_drugs"]:
                # do stuff
                if ok:
                    return drug_costs

Now, perhaps reformulating your logic like this is tricky, but I bet the refactoring will help in other ways.

john_science
  • 6,325
  • 6
  • 43
  • 60
2

Untested:

inner_termination=False
for row in b:
    for drug in drug_input:
       for brand in brand_names[drug]:
           <blah>
           if break_condition:
               inner_termination=True
               break 
           <blah>
       if inner_termination:
           inner_termination=False
           break 
Caleb Hattingh
  • 9,005
  • 2
  • 31
  • 44
2
for row in b:
    ok = True
    for drug in drug_input:
        if not ok:
            break;
        for brand in brand_names[drug]:
            if not ok:
                break
            if whatever:
                ok = False
Teodor Pripoae
  • 1,388
  • 1
  • 11
  • 26
2

try/except/raise, as suggested in @gddc's comment, is one possibility. Another one is to "wrap up" the two nested loops into one:

for row in b:
  for brand in (b for d in drug_input for b in brand_names[d]):
    ...

now, a break from the for brand nested loop will go back to the for row outer loop level. Of course, this works only when the code that is here replaced by ... does not need to see the drug name bound to the drug currently being examined. Is that the case for you?

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • Simple enough to get the drug name it is required. `for brand, drug in ((b,d) for d in drug_input for b in brand_names[d]):` – John La Rooy Jul 29 '10 at 14:40