In Python, exception handling is done using try
, except
, else
, and finally
blocks. While most of the focus tends to be on try
and except
, the else
and finally
blocks add additional control and flexibility to exception handling. These blocks help in managing the flow of code after exceptions are caught or avoided, and they ensure that necessary cleanup is always performed.
1. The else
Block in Exception Handling
The else
block is an optional part of exception handling that is executed if the try
block does not raise an exception. This is particularly useful when you want to separate the code that runs when there are no errors from the error-handling code. The code inside the else
block only runs if no exception is raised within the try
block.
Syntax:
try:
# Code that may raise an exception
risky_code()
except SomeException:
# Code to handle the exception
handle_error()
else:
# Code that runs only if no exception occurs
code_if_no_error()
Example: Using else
in Exception Handling
try:
x = 10 / 2 # This will work fine
except ZeroDivisionError:
print("Cannot divide by zero!")
else:
print(f"Division successful! The result is {x}")
Output:
Division successful! The result is 5.0
Explanation:
- The
try
block executes the division operation. - Since there is no error (no
ZeroDivisionError
), the code inside theelse
block runs, printing the result. - If there had been an error, the
else
block would have been skipped.
2. The finally
Block in Exception Handling
The finally
block is also optional but is used to define code that should always execute, regardless of whether an exception was raised or not. This is especially useful for cleanup tasks such as closing files, releasing resources, or performing actions that must occur after the try
block, no matter what.
Even if an exception is raised and caught, or if the program exits the try
block normally, the code inside finally
will run.
Syntax:
try:
# Code that may raise an exception
risky_code()
except SomeException:
# Code to handle the exception
handle_error()
finally:
# Code that always runs, regardless of exception occurrence
cleanup_code()
Example: Using finally
for Cleanup
try:
file = open("example.txt", "r") # Try to open a file
content = file.read() # Read file content
except FileNotFoundError:
print("File not found!")
finally:
if 'file' in locals():
file.close() # Close the file, whether an error occurred or not
print("File has been closed.")
Output:
File not found!
File has been closed.
Explanation:
- The
try
block attempts to open and read from a file. - If the file is not found, the
except
block is executed, printing an error message. - Regardless of whether an error occurred or not, the
finally
block is executed, ensuring that the file is closed if it was successfully opened.
3. Using else
and finally
Together
You can combine both else
and finally
blocks in a try-except
statement. While else
handles the situation when no exceptions are raised, finally
ensures that certain actions (like cleanup) always occur, no matter what.
Syntax:
try:
# Code that may raise an exception
risky_code()
except SomeException:
# Code to handle the exception
handle_error()
else:
# Code that runs only if no exception occurs
code_if_no_error()
finally:
# Code that always runs, regardless of exception occurrence
cleanup_code()
Example: Using else
and finally
Together
try:
result = 10 / 2 # This will succeed
except ZeroDivisionError:
print("Cannot divide by zero!")
else:
print(f"Division successful! The result is {result}")
finally:
print("Cleaning up resources...")
Output:
Division successful! The result is 5.0
Cleaning up resources...
Explanation:
- The
try
block attempts to divide the numbers. - The
else
block runs because no exception occurs, printing the division result. - The
finally
block runs after theelse
block, regardless of whether an exception occurred or not, ensuring cleanup actions are performed.
4. Key Points to Remember
When to Use else
:
- Use the
else
block when you want to separate the normal execution flow (the code that should run if no exceptions occur) from the exception handling logic. - It’s helpful for code that should only run if the
try
block is successful, such as logging success, or performing additional tasks that are contingent on no errors.
When to Use finally
:
- Use the
finally
block to ensure that specific code runs regardless of what happens in thetry
andexcept
blocks. - This is typically used for cleanup actions like closing files, releasing network resources, or other essential tasks that must happen whether or not an error occurred.
Order of Execution:
try
: The code that might raise an exception is placed here.except
: If an exception is raised, the code in this block is executed.else
: If no exception occurs in thetry
block, this block is executed.finally
: This block always executes after thetry
(and optionally afterexcept
orelse
).
Important:
- If the
try
block executes without errors, theexcept
block is skipped, theelse
block executes, and then thefinally
block runs. - If an exception occurs, the
except
block handles the error, theelse
block is skipped, and thefinally
block executes. - The
finally
block executes whether an exception is raised or not.
5. Example: Putting it All Together
def divide_numbers(a, b):
try:
result = a / b
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
else:
print(f"Result: {result}")
finally:
print("Execution complete, cleaning up resources...")
divide_numbers(10, 2)
divide_numbers(10, 0)
Output:
Result: 5.0
Execution complete, cleaning up resources...
Error: Cannot divide by zero.
Execution complete, cleaning up resources...
Explanation:
- In the first call (
divide_numbers(10, 2)
), there is no exception, so theelse
block runs and prints the result, followed by thefinally
block. - In the second call (
divide_numbers(10, 0)
), aZeroDivisionError
occurs, so theexcept
block handles the error, and thefinally
block executes afterward.