🤯TIL for...else exists in Python
Today, I learned that you can pair an else
clause with a loop statement such as for
or while
. It looks like this:
for i in iterator:
# do something
else:
# do something else
This may look quite counterintuitive for the first time, but we will unwrap it in a moment! ✨
First, let's review the basic syntax of a for
loop in Python. A for
loop allows you to iterate over an iterator (such as a list, tuple, or string) and execute a block of code for each value. Here's an example:
fruits = ['apple', 'banana', 'cherry']
for fruit in fruits:
print(fruit)
This code would output:
apple
banana
cherry
Simple example
Now, let's add an else
clause to this loop:
fruits = ['apple', 'banana', 'cherry']
for fruit in fruits:
print(fruit)
else:
print("No more fruits")
This code would output:
apple
banana
cherry
No more fruits
In this case, the else
block is executed after the for
loop has finished normally. If the loop is exited early (for example, by a break
statement), the else
block will not be executed.
Linear search example
This for..else
can be quite helpful in some scenarios. For example, you can use it to check if a value exists in a list:
values = [1, 2, 3, 4, 5]
for value in values:
if value == 6:
print("Value found!")
break
else:
print("Value not found.")
Let's take a look at another version without using for...else
:
values = [1, 2, 3, 4, 5]
found = False
for value in values:
if value == 6:
found = True
break
if found:
print("Value found!")
else:
print("Value not found.")
You can see, we have to introduce a boolean flag if we do not use the else
clause. This makes the control flow more complex.
Breaking out of nested loops
In Python, the break
statement only terminates the nearest enclosing loop. In some cases, you may want to break out of a parent loop.
Consider this code that determines if n
is a prime number:
n = 11
if n <= 1:
print(f"{n} is not a prime number!")
exit()
for i in range(2, n):
for j in range(2, n):
if i * j == n:
print(f"{n} is not a prime number!")
break
else:
continue # only executed if the inner loop did NOT break
break # only executed if the inner loop DID break
else:
print(f"{n} is a prime number!")
It works by iterating over all pairs of numbers (i, j)
less than n
and checking if the product of any of them is equal to n
. In the case where we find i * j
is equal to n
, we can say that n
is not a prime number and we would want to exit the outer for
loop early.
If the inner loop completes successfully (i.e., without breaking), it means that no pairs of numbers were found whose product equals n
. In this case, the else
clause of the inner loop is executed. This else
clause triggers the continue
statement, which causes the outer loop to immediately proceed to the next value of i
without executing the remaining code in the outer loop.
If the inner loop breaks at any point, the else
clause of the inner loop is skipped and the outer loop would reach the break
statement, which breaks the outer loop as well.
PEP 3136 is a Python Enhancement Proposal that proposes support for labels in break
and continue
statements. However, it was rejected due to the complexity it would add to Python.
The example I have shown above is one of the workarounds that produce clean code. Another solution is to put the code in a function and use return
instead. Using a function is usually preferred because code with low cyclomatic complexity is usually more maintainable.