Error Handling in Python
Handling errors is essential in programming. It helps your program deal with unexpected situations without crashing, making it more reliable. Good error management lets you show helpful messages to users, explaining what went wrong and what to do next. It also makes finding and fixing bugs during development easier and prevents exposing sensitive information, reducing security risks.
In this tutorial, we will learn all about the errors and how to handle them in Python.
Syntax Errors
In Python, there are 3 main types of errors: syntax errors, runtime errors (exceptions), and logical errors. First, we will understand about the syntax errors.
Syntax errors happen when Python doesn’t understand the code because it doesn’t follow the correct rules. These errors are usually caught before the program starts running.
When encountering a syntax error, the Python interpreter provides an error message that typically includes information about the specific error and the location (line number) where it occurred. It’s important to carefully read the error message and examine the corresponding line of code to identify and fix the syntax mistake.
Common causes of syntax errors
Missing Colons: Forgetting a colon (:
) at the end of statements like if
, for
, while
, or def
.
if True print("Hello, World!")
Indentation Errors: Python uses indentation (spaces or tabs) to define blocks of code. Incorrect indentation can cause errors.
def my_function(): print("Hello, World!") # This line should be indented
Unmatched Parentheses: Missing or mismatched parentheses, brackets, or braces.
print("Hello, World!" # Missing closing parenthesis
Spelling Mistakes in Keywords: Misspelling Python keywords or using them incorrectly.
fro i in range(5): # Should be 'for' print(i)
Incorrect Use of Quotes: Mixing up single and double quotes for strings.
print('Hello, World!") # Mixing single and double quotes
Runtime Errors (Exceptions)
Runtime errors, also known as exceptions, occur while the program is running. Unlike syntax errors, which prevent the code from running, exceptions occur during execution and can cause the program to stop if not handled properly.
Common Runtime Errors in Python
ZeroDivisionError: This error occurs when you try to divide a number by zero.
Example:
numerator = 10 denominator = 0 result = numerator / denominator # ZeroDivisionError: division by zero
Output:
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-38-59845a5e685f> in <module>
1 numerator = 10
2 denominator = 0
----> 3 result = numerator / denominator # ZeroDivisionError: division by zero
ZeroDivisionError: division by zero
TypeError: This error happens when an operation is applied to an object of an inappropriate type.
Example:
num1 = 10 num2 = "5" result = num1 + num2 # TypeError: unsupported operand type(s) for +: 'int' and 'str'
Output:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-39-1bc61e03907d> in <module>
1 num1 = 10
2 num2 = "5"
----> 3 result = num1 + num2 # TypeError: unsupported operand type(s) for +: 'int' and 'str'
TypeError: unsupported operand type(s) for +: 'int' and 'str'
ValueError: This error is raised when a function receives an argument of the correct type but an inappropriate value.
Example:
age = int("twenty") # ValueError: invalid literal for int() with base 10: 'twenty'
Output:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-40-ef2a33a50e84> in <module>
----> 1 age = int("twenty") # ValueError: invalid literal for int() with base 10: 'twenty'
ValueError: invalid literal for int() with base 10: 'twenty'
IndexError: This error occurs when you try to access an index that is out of the range of a list or other sequence.
Example:
my_list = [1, 2, 3] print(my_list[3]) # IndexError: list index out of range
Output:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-41-22703a3eb9f0> in <module>
1 my_list = [1, 2, 3]
----> 2 print(my_list[3]) # IndexError: list index out of range
IndexError: list index out of range
KeyError: This error happens when you try to access a dictionary with a key that does not exist.
Example:
my_dict = {"name": "John", "age": 25} print(my_dict["address"]) # KeyError: 'address'
Output:
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-42-49b622964952> in <module>
1 my_dict = {"name": "John", "age": 25}
----> 2 print(my_dict["address"]) # KeyError: 'address'
KeyError: 'address'
AttributeError: This error occurs when you try to access an attribute or method that does not exist for an object.
Example:
my_string = "Hello, World!" print(my_string.uppercase()) # AttributeError: 'str' object has no attribute 'uppercase'
Output:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-43-bcf7dc35cdc3> in <module>
1 my_string = "Hello, World!"
----> 2 print(my_string.uppercase()) # AttributeError: 'str' object has no attribute 'uppercase'
AttributeError: 'str' object has no attribute 'uppercase'
FileNotFoundError: This error is raised when trying to open a file that does not exist.
Example:
file = open("nonexistent.txt") # FileNotFoundError: [Errno 2] No such file or directory:'nonexistent.txt'
Output:
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-44-353eb93ba8a6> in <module>
----> 1 file = open("nonexistent.txt") # FileNotFoundError: [Errno 2] No such file or directory:'nonexistent.txt'
FileNotFoundError: [Errno 2] No such file or directory: 'nonexistent.txt'
These are just a few examples of common runtime errors in Python. To prevent these runtime errors from crashing your program, you can use try-except blocks. We will learn about it in later sections.
Logical Errors
Logical errors occur when a program runs without crashing but produces incorrect results. These errors are due to flaws in the program’s logic, and they can be tricky to detect because there are no error messages indicating what went wrong.
Example 1: Incorrect Formula
def calculate_area(length, width): # Intent: Calculate the area of a rectangle return length + width # Logical error: should be length * width area = calculate_area(5, 10) print(area) # Output: 15, but should be 50
Example 2: Incorrect Condition
def check_even(number): # Intent: Check if the number is even if number % 2 == 1: # Logical error: should be number % 2 == 0 return True return False is_even = check_even(4) print(is_even) # Output: False, but should be True
Strategies to Minimize Logical Errors
- Code Reviews: Having another set of eyes review your code can help catch logical errors. Peers can often spot mistakes that you might overlook.
- Unit Testing: Writing tests for individual functions and methods ensures that each part of your code behaves as expected.
- Debugging: Use debugging tools to step through your code and inspect variables and their values at different points. This helps you understand how the code is executed and where it might be going wrong.
- Print Statements: Insert print statements at key points in your code to check the flow and values of variables.
- Refactor Code: Break down complex functions into smaller, manageable pieces. This makes it easier to identify and fix logical errors.
The try-except Block
The try-except
block is a way to handle runtime errors, known as exceptions in Python without stopping your program. It lets you “try” a piece of code, and if something goes wrong, you can “except” (or catch) the error and handle it.
Syntax:
try: # Code that might raise an error except SomeError: # Code to run if an error happens
Example: Handling ZeroDivisionError
try: numerator = 10 denominator = 0 result = numerator / denominator print("Result:", result) except ZeroDivisionError: print("Error: Division by zero is not allowed.")
In this example, the code inside the try
block attempts to perform a division. However, since the denominator is zero, a ZeroDivisionError
occurs. The exception is caught by the except
block, which prints an error message.
Output:
Error: Division by zero is not allowed.
Handling Multiple Exceptions
You can handle different types of exceptions by specifying multiple except
blocks. Each except
block can handle a specific type of exception.
Syntax:
try: # Code that might raise multiple exceptions except FirstException: # Code to handle the first type of exception except SecondException: # Code to handle the second type of exception
Example: Handling TypeError and ValueError
try: num1 = 10 num2 = "5" result = num1 + num2 print("Result:", result) except TypeError: print("Error: Invalid operation between different types.") except ValueError: print("Error: Invalid value provided.")
In this example, the code inside the try
block attempts to add an integer and a string. Since it’s an invalid operation, a TypeError
occurs, and the first except
block is executed, printing an appropriate error message.
Output:
Error: Invalid operation between different types.
Single except Block for Multiple Exceptions
You can also use a single except
block to catch multiple types of exceptions by listing them as a tuple.
Example: Handling ZeroDivisionError and ValueError
try: num = int(input("Enter a number: ")) result = 10 / num except (ZeroDivisionError, ValueError): print("Error: Either you entered an invalid number or tried to divide by zero.")
When you are handling different Exception types, always handle specific exceptions before more general ones. Python processes except
blocks in the order they are written so place the most specific exceptions first.
Handling Generic Exceptions
You can use a generic except block to handle any exception that is not specifically caught by other except blocks.
Example: Handling Generic Exceptions
try: # Some code that may raise exceptions except Exception as e: print("An error occurred:", e)
In this example, the except Exception
as “e” block catches any exception that occurs and assigns it to the variable e
. We can then print a generic error message along with the specific exception details.
Remember, unless you have a good reason, avoid catching all exceptions with a single except Exception
block, as it can make debugging difficult.
The else and finally Blocks in Exception Handling
When dealing with errors in Python, sometimes you want to run some code only if no errors happen, or you might need to make sure certain code always runs, no matter what. For this, you can use optional else
and finally
blocks.
The else Block
The else
block in Python is used with try-except
blocks. It lets you run code only if no exceptions (errors) are raised in the try
block. This way, you can separate your error-handling code from the code that should run when everything goes smoothly.
Example:
try: num = int(input("Enter a number: ")) result = 10 / num except ZeroDivisionError: print("Oops! You can't divide by zero!") except ValueError: print("Please enter a valid number.") else: print("Division successful! The result is:", result)
The finally Block
The finally
block is for code that should run no matter what happens in the try
and except
blocks. This is useful for cleanup tasks, like closing a file or releasing a resource.
Example: Using else and finally Blocks
try: file = open("example.txt", "r") content = file.read() except FileNotFoundError: print("The file doesn't exist.") else: print("File read successfully!") finally: file.close() print("File closed.")
Raising Exceptions
Sometimes, you might want to intentionally trigger an error in your code to handle specific situations or enforce certain rules. This is done using the raise
statement.
The raise
statement allows you to trigger an exception. This is useful when you want to signal that an error has occurred or some condition has not been met.
Syntax:
raise ExceptionType("Error message")
ExceptionType
: This is the type of exception you want to raise. Python has several built-in exceptions that you can raise in your code (e.g., ValueError
, TypeError
, IndexError
).
"Error message"
: This is an optional message that provides more details about the error.
Example:
def check_positive_number(num): if num <= 0: raise ValueError("The number must be positive.") return num try: check_positive_number(-5) except ValueError as e: print("Error:", e)
Raising Custom Exceptions
If you need more specific exceptions that are not covered by built-in ones. You can create your own custom exceptions by defining a new class that inherits from the Exception
class.
Example:
class NegativeNumberError(Exception): pass def check_positive_number(num): if num < 0: raise NegativeNumberError("Negative numbers are not allowed.") return num try: check_positive_number(-5) except NegativeNumberError as e: print("Error:", e)