7

I am trying to iterate through a list, and I need to perform specific operation when and only when the iteration reached the end of the list, see example below:

data = [1, 2, 3]

data_iter = data.__iter__()
try:
    while True:
        item = data_iter.next()
        try:
            do_stuff(item)
            break # we just need to do stuff with the first successful item
        except:
            handle_errors(item) # in case of no success, handle and skip to next item
except StopIteration:
    raise Exception("All items weren't successful")

I believe this code isn't too Pythonic, so I am looking for a better way. I think the ideal code should look like this hypothetical piece below:

data = [1, 2, 3]

for item in data:
    try:
        do_stuff(item)
        break # we just need to do stuff with the first successful item
    except:
        handle_errors(item) # in case of no success, handle and skip to next item
finally:
    raise Exception("All items weren't successful")

Any thoughts are welcome.

twasbrillig
  • 17,084
  • 9
  • 43
  • 67
Serge Tarkovski
  • 1,861
  • 6
  • 19
  • 24
  • replace `finally` with `else`? – Reinstate Monica Jul 05 '12 at 20:29
  • Why do you have `'All items weren't successful'` instead of `"All items weren't successful"`? That middle apostrophe will break your string/exception if it runs. Also, to WolframH's point, see the [docs](http://docs.python.org/reference/compound_stmts.html#for) - `else` instead of `finally` should work. – thegrinner Jul 05 '12 at 20:31
  • 1
    It's worth noting that `except:` is a terrible thing - if it's just for example, fine, but in any real example, please only catch a specific exception. – Gareth Latty Jul 05 '12 at 20:34
  • Yes... `except Exception` at a minimum. – FogleBird Jul 05 '12 at 20:34
  • @thegrinner fixed, it was just mistype in a quick-and-dirty code to demonstrate the problem – Serge Tarkovski Jul 05 '12 at 20:43
  • @Lattyware thanks, I never use such `except:` in real code, as I've said, this is just quick-and-dirty example – Serge Tarkovski Jul 05 '12 at 20:44
  • @FogleBird `except Exception:` is almost worse - people expect it to catch everything and it won't. Catching a specific exception is always what you want. – Gareth Latty Jul 05 '12 at 21:44
  • I think it's much better than a bare except. `except Exception:` catches everything that you'd normally want to catch. It *doesn't* catch things like `KeyboardInterrupt`... which is usually the desired behavior. But yes, specific exceptions are always best. – FogleBird Jul 06 '12 at 00:42

1 Answers1

18

You can use else after a for loop, and the code within that else is only executed if you did not break out of the for loop:

data = [1, 2, 3]

for item in data:
    try:
        do_stuff(item)
        break # we just need to do stuff with the first successful item
    except Exception:
        handle_errors(item) # in case of no success, handle and skip to next item
else:
    raise Exception("All items weren't successful")

You can find this in the documentation for the for statement, relevant pieces shown below:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

A break statement executed in the first suite terminates the loop without executing the elseclause’s suite.

Andrew Clark
  • 202,379
  • 35
  • 273
  • 306