for ... else in Python

Python has an interesting for statement (reference) which lets you specify an else suite.

In a construct like this one:

for i in foo:
  if bar(i):
    break
else:
  baz()

the else suite is executed after the for, but only if the for terminates normally (not by a break).

Here's some code written without for...else:

def contains_even_number(l):
  "Prints whether or not the list l contains an even number."
  has_even_number = False
  for elt in l:
    if elt % 2 == 0:
      has_even_number = True
      break
  if has_even_number:
    print "list contains an even number"
  else:
    print "list does not contain an even number"

The equivalent code snippet below illustrates how the use of for...else lets you remove an extraneous flag variable from that loop:

def contains_even_number(l):
  "Prints whether or not the list l contains an even number."
  for elt in l:
    if elt % 2 == 0:
      print "list contains an even number"
      break
  else:
    print "list does not contain an even number"

Use your good judgment when deciding whether to use the for...else construct. It's not unequivocally better, but when there's an asymmetry between the two possibilities, you can make your code more readable by using for...else to keep the "happy path" logic at the top and the exceptional/error case at the bottom.

8 comments:

  1. Good post. Thanks

    ReplyDelete
  2. Of course you could do:

    from __future__ import print_function
    contains_even_number = lambda l: print("list contains an even number") if any(elt % 2 == 0 for elt in l) else print("list does not contain an even number")

    But this is still useful for lots of things! Thanks!

    ReplyDelete
  3. I've seen this before, and you just gave the first example that made it seem sort of useful, but I still feel like its creepily unintuitive that the else block only executes if the block above it also executes. . .

    ReplyDelete
  4. Very interesting, but I agree with ekspiulo - seems a bit unintuitive.

    ReplyDelete
  5. Fun trivia fact: this language feature was added sometime around the first public release of Python. It's nearly twenty years old!

    ReplyDelete