Loop once... (f)or else! (Or, Python pro-tip number 2)
Once upon a time, some seven years ago, I wrote a post about a Python trick for accessing the first element of any kind of sequence.
The gist of that article is that just using indexing isn’t general enough: if the sequence is
lazily computed by a generator, then indexing won’t work.
What does work, however, is to iterate over the sequence using a
for loop. But since we just want
the first element, let’s immediately break out of the loop.
for x in seq: print(x) # or do whatever break
But there’s something I missed in that post! What if the sequence is empty?
An obvious solution is to use a boolean:
= False entered for x in seq: = True entered print(x) break if not entered: pass # do whatever
But that’s pretty ugly if not outright disgusting. Instead, we can take advantage of a
little-known feature of Python’s for-loops: in Python, a for-loop can have an
else block! The
semantics are that if the loop terminates normally, then the
else-block is run; else, if the
loop exits early, e.g. by a
break, then the
else-block is skipped.
These semantics are frankly weird to me, but they end up working out marvellously for our current
use case. It almost makes me think that this is why
else was allowed in the first place for a
for-loop. Consider this.
for x in seq: print(x) break else: print("nothing in the sequence")
If the sequence is nonempty, then we will print the first item in the sequence and abort the loop,
else-block. If the sequence is empty, then the loop will exit normally, so the
else-block will run!