Mastering Python Exception Handling (try-except)
To run Python from the command prompt or PowerShell on your PC, you need to download and install Python.
If you haven’t installed it yet, please refer to the article Setting Up Python and Development Environment to install Python.
When writing programs, encountering unexpected errors is inevitable. The causes of errors are varied, such as incorrect user input, non-existent files, or network issues. "Exception handling" is the mechanism that prevents your program from suddenly crashing and allows you to respond intelligently.
In this article, we'll explain the basics and applications of exception handling using Python's try-except statement in a way that's easy for beginners to understand, complete with code examples you can copy and paste to run immediately. Let's master how to build robust, error-resistant programs by experiencing "working" code firsthand!
The Basics First! The try-except Syntax
The most fundamental form of exception handling is the try-except statement. As the name suggests, it creates a flow: "try this, and if an exception (error) occurs, except (catch and handle) it."
The syntax is very simple.
- Inside the
tryblock, you write the code that might cause an error. - Inside the
exceptblock, you write the code you want to execute when an error occurs.
Seeing is believing. Let's look at the famous "ZeroDivisionError" as an example. The code below attempts to divide 10 by 0. Normally, this would crash the program with an error, but with try-except, we can catch it properly.
<!-- Python Code -->
try:
# Code that might cause an error
result = 10 / 0
print(f"Calculation result: {result}")
except ZeroDivisionError:
# Action to take if a ZeroDivisionError occurs
print("Oops! You can't divide by zero.")
print("The program finished normally.")
Targeting Specific Exceptions! Multiple excepts
In programming, various types of errors can occur. For example, with user input, you might get a "ValueError" (when a string is entered instead of a number), or with file operations, a "FileNotFoundError" (when the specified file doesn't exist).
By specifying the type of error (the exception class) after the except statement, you can catch only specific errors and perform appropriate actions for each.
Furthermore, by lining up multiple except blocks, you can write different handlers for different types of errors. The following example tries to convert a string to an integer.
<!-- Python Code -->
user_input = "hello" # A string, not a number
try:
num = int(user_input)
print(f"Entered number: {num}")
except ValueError:
print("Please enter a number! A string cannot be converted to a number.")
except TypeError:
print("Type mismatch! The type is not convertible to a number.")
print("Continuing processing...")
You'll often want to know the detailed information (error message) of an error that occurred. In that case, you can use as to store the exception object in a variable. The variable name e (initial for error or exception) is commonly used.
<!-- Python Code -->
try:
# Attempt to open a non-existent file
with open("non_existent_file.txt", "r") as f:
content = f.read()
except FileNotFoundError as e:
# Display detailed error information
print(f"File not found.")
print(f"Error details: {e}")
Advanced Usage: Mastering else and finally
The try-except statement has two powerful companions: else and finally. Combining them allows for more fine-grained control.
- else block: This executes only if no exception occurred in the
tryblock. It's useful for cleanly separating normal processing from error handling. - finally block: This is always executed at the end, regardless of whether an exception occurred. It's perfect for writing cleanup code, like closing files or network connections.
Let's look at some code that uses all these elements.
<!-- Python Code -->
file_path = "my_data.txt"
data_to_write = "This is test data."
try:
print(f"Writing data to '{file_path}'...")
f = open(file_path, "w", encoding="utf-8")
# To intentionally cause an error, uncomment the next line
# f.write(12345) # TypeError occurs if trying to write non-string data
f.write(data_to_write)
print("Attempted to write.")
except TypeError as e:
print(f"Error! Data to write must be a string.")
print(f"Error details: {e}")
except Exception as e:
# Catch any other unexpected errors
print(f"An unexpected error occurred.")
print(f"Error details: {e}")
else:
# Executes if no exception occurred in the try block
print("Successfully wrote to the file!")
finally:
# Always executes, regardless of exceptions
if 'f' in locals() and not f.closed:
f.close()
print("File has been closed.")
else:
print("File was not open or was already closed.")
print("--- Processing Complete ---")
Hands-On! A Complete, Runnable Code Example
Now, let's use everything we've learned to create a more practical program. This code asks the user for their age and repeatedly prompts them until a valid number is entered. It then saves the entered age to a file. Potential errors along the way are handled by try-except.
Copy the entire code below, save it as a file named age_logger.py, and run it in your terminal with python age_logger.py. Try intentionally entering text to see how the error handling works!
<!-- Full Python Script: age_logger.py -->
import datetime
def record_age():
"""
A function to ask for the user's age and record it to a file.
Handles input validation and file I/O errors.
"""
while True:
try:
# Receive input from the user
age_str = input("Please enter your age as a number: ")
# Convert the string to an integer
age = int(age_str)
# Check for negative values or unrealistic ages
if age < 0 or age > 130:
# Raise a custom error
raise ValueError("Age must be between 0 and 130.")
# If a valid age is entered, break the loop
break
except ValueError as e:
# Catch ValueError from int() conversion or the raised one
print(f"Error: {e}")
print("Please try again with a valid number.\n")
# Record to file
try:
# The with statement automatically closes the file, so a finally block for close() is not needed
with open("age_log.txt", "a", encoding="utf-8") as f:
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
f.write(f"[{timestamp}] Recorded Age: {age}\n")
print(f"Your age, '{age}', has been recorded to 'age_log.txt'.")
except IOError as e:
# Catch errors like lack of file write permissions
print("Fatal Error: Failed to write to the file.")
print(f"Error details: {e}")
if __name__ == "__main__":
record_age()
print("Thank you for using the program.")
Points to Watch Out For: Catching Broad Exceptions
Exception handling is useful, but misusing it can make it harder to find problems in your program. A particular point of caution is catching exceptions that are too broad.
Not Recommended: Bare except
The worst practice is a "bare except:" that doesn't specify an exception class. This indiscriminately catches all errors. This includes SystemExit, which is used to terminate the program, and even KeyboardInterrupt from pressing Ctrl+C. You could end up in a situation where you can't even stop your program when you want to.
Use with Caution: except Exception
except Exception as e: is better than a bare except:, but it still catches most common errors. During development, you often want errors to occur to find unexpected bugs. If you catch everything, bugs that should be fixed can be hidden.
The best practice is to "specify and catch only those exceptions that you can predict and handle appropriately."
Summary and Next Steps
In this article, we learned about Python's try-except statement for exception handling. Let's review the key points.
- You can prevent program crashes due to errors with
try-except. - With
except ExceptionClass as e, you can catch specific errors and get detailed information. - Use
elsefor success cases andfinallyfor cleanup operations. - The trick is to narrow down exception catching to specific, handleable cases rather than being too broad.
By mastering exception handling, you can build robust applications that are user-friendly and easy for developers to maintain. Be sure to introduce try-except into your own code.
As a next step, why not learn about an important concept for modularizing your program and increasing its reusability?
>> Next Article: Introduction to Python Classes and Object-Oriented Programming