In most programming languages like C, Java and Javscript, the else clause is used with if statements. But did you know in Python the while and for loops as well as the try statement can also have else clauses?
In the while loop
To get a sense of how the else works with the loops, it's easy to write some code to play with. Here's the first one I tried:
basket = ["apple", "orange", "pear", "banana"]
i = 0
while basket[i] != "apple":
print(f"Its not {i}")
i = i + 1
else:
print("Else block ran!")
print(f"i is now {i}")
What do you think will be the output? At first, I thought it would output Else block ran! followed by i is now 0 (i.e. it would execute the else block) because the first item in the list is already apple. The output certainly shows this happens:
Else block ran!
i is now 0
But, what if we changed the condition in the while loop to basket[i] != "banana"? The body of the while loop should now run, so I first thought it would surely skip the else clause ...
Its not 0
Its not 1
Its not 2
Else block ran!
i is now 3
Nope! It printed Else block ran!, so the else block must've ran!
So what's going on here? Turning to the documentation on the while statement:
This repeatedly tests the expression and, if it is true, executes the first suite; if the expression is false (which may be the first time it is tested) the suite of the
elseclause, if present, is executed and the loop terminates.A
breakstatement executed in the first suite terminates the loop without executing theelseclause’s suite.
So, if we want to skip the else block, loop needs to exit with a break.
Rewriting the while loop to use break to exit when it finds a match:
basket = ["apple", "orange", "pear", "banana"]
i = 0
while i < len(basket):
if basket[i] == "banana":
# We found what we were looking for.
break
print(f"Its not {i}")
i = i + 1
else:
# We couldn't find it in the list.
print("Else block ran!")
print(f"i is now {i}")
The output now doesn't contain the print in the else block:
Its not 0
Its not 1
Its not 2
i is now 3
And just to check, setting the if condition back to basket[i] == "apple" also doesn't run the else block:
i is now 0
In the for loop
The behaviour of the else clause in the for loop is the same as that of the while loop. Rewriting the while loop to use for instead:
basket = ["apple", "orange", "pear", "banana"]
find = "banana"
for f in basket:
if f == find:
print(f"We found {find}!")
break;
else:
print(f"There isn't any {find}!")
Running this, you'll get the output We found banana!, but changing find to "grape" will result in There isn't any grape!.
In try statements
For the else in try statements, the documentation states:
The optional
elseclause is executed if the control flow leaves thetrysuite, no exception was raised, and noreturn,continue, orbreakstatement was executed. Exceptions in the else clause are not handled by the precedingexceptclauses.
Here's an example of a try with an else clause:
try:
# This will raise an AssertionError
assert 1 == 2
except:
# Catch all exceptions
print("Got exception")
else:
print("Else!")
finally:
# Finally always runs at the end
print("Finally!")
With the AssertionError thrown, it skips the else. This is the output:
Got exception
Finally!
But changing the assertion to pass (e.g. assertion 1 == 1), no exception is thrown and, thus, else is executed:
Else!
Finally!
However, you could do the same thing without an else clause - anything within the try block after the line that can throw the exception is effectively the "else". For example:
try:
# If this assertion fails, this will throw an AssertionError
assert 1 == 1
# No exception thrown, so everything here is the "else"
print("Else!")
except:
# Catch all exceptions
print("Got exception")
finally:
# Finally always runs at the end
print("Finally!")
So given this alternative, apart from style, why would you use the else clause? The difference is in when the else block throws an exception (thanks to this Stackoverflow answer for pointing it out). If it's part of the try block, the exception may be handled by one of the try's except handlers, but it's passed up the chain if it's in an else clause - none of the handlers defined in the same try statement will handle exceptions from the else.
To see this, let's modify the try statement so that the assert becomes the else. First, without the separate else clause:
try:
# Body of try. Won't throw an exception.
print("Try body")
# The "else" part. Make it throw an exception.
assert 1 == 2
except:
# Catch all exceptions
print("Got exception")
finally:
# Finally always runs at the end
print("Finally!")
The output for this is:
Try body
Got exception
Finally!
Notice the except block handled the exception from our "else". So to check that using the else clause doesn't trigger one of the handlers:
try:
# Body of try
print("Try body")
except:
# Catch all exceptions
print("Got exception")
else:
# Make else thrown an exception
assert 1 == 2
finally:
# Finally always runs at the end
print("Finally!")
Which gives the following output:
Try body
Finally!
Traceback (most recent call last):
File "main.py", line 9, in <module>
assert 1 == 2
AssertionError
Top comments (0)