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
else
clause, if present, is executed and the loop terminates.A
break
statement executed in the first suite terminates the loop without executing theelse
clause’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
else
clause is executed if the control flow leaves thetry
suite, no exception was raised, and noreturn
,continue
, orbreak
statement was executed. Exceptions in the else clause are not handled by the precedingexcept
clauses.
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)