Python Errors and Exceptions

In this section, we'll explore how Python handles errors and exceptions. Errors can occur during the execution of a program, but Python provides mechanisms to handle them gracefully. We’ll dive into the different types of errors, how to handle exceptions with the try-except block, and more advanced exception-handling techniques.



Types of Errors in Python

In Python, errors are classified into different types. These errors can be broadly categorized into two groups: syntax errors and runtime errors. Here's an overview of each type:

  • Syntax Errors: Occur when the Python interpreter encounters invalid syntax. These errors prevent the program from running. For example, missing parentheses or incorrect indentation.
  • Runtime Errors: Occur when the program runs, but encounters an issue that prevents further execution, such as division by zero, accessing an undefined variable, etc.
  • Logic Errors: These errors don't cause the program to crash but lead to incorrect results due to flawed logic in the code.

1. Example of a Syntax Error

A syntax error happens when Python cannot understand the code due to incorrect formatting. It might be caused by missing punctuation, parentheses, or improper indentation.

python
# Missing closing parenthesis causes a syntax error
print("Hello, world!"

Output:

SyntaxError: unexpected EOF while parsing

2. Example of a Runtime Error

A runtime error occurs when the program is running, but something goes wrong during execution. This could be caused by invalid operations like dividing by zero or trying to access an undefined variable.

python
# Division by zero causes a runtime error
x = 10
y = 0
print(x / y)

Output:

ZeroDivisionError: division by zero

3. Example of a Logic Error

A logic error occurs when the code runs without crashing, but the results are incorrect due to an error in the logic of the program. The program will not raise an exception, but the output will not be what you expect.

python
# Logic error: incorrect calculation of average
numbers = [10, 20, 30, 40, 50]
sum_of_numbers = sum(numbers)
count_of_numbers = len(numbers)
average = sum_of_numbers // count_of_numbers  # Incorrect use of integer division
print(f"The average is {average}")

Output:

The average is 30

In the above code, integer division was used for calculating the average, which causes the result to be incorrect. It should have used normal division ("/") instead of floor division ("//").


What Are Exceptions?

Exceptions are a way for Python to indicate that an error has occurred. Instead of letting the program continue running in an invalid state, Python raises exceptions to signal that something unexpected happened. Once raised, an exception can either be handled by a programmer or, if left unhandled, it can cause the program to crash.

Why Do Exceptions Happen?

Exceptions happen due to various errors in the code, such as:

  • Incorrect operations: Operations that are not supported by the data type, like trying to add a string and an integer.
  • Accessing out-of-range indices: Trying to access elements of a sequence using indices that do not exist.
  • Invalid input: Passing incorrect types or values to functions, such as trying to convert a non-numeric string to an integer.
  • File operations: Attempting to open, read, or write to a file that does not exist.

Common Python Exceptions:

ExceptionDescription
SyntaxErrorRaised when the Python interpreter encounters invalid syntax in the code.
ZeroDivisionErrorRaised when a division or modulo operation is performed with zero as the divisor.
NameErrorRaised when a local or global name is not found. This typically happens when you reference a variable that hasn't been defined.
IndexErrorRaised when trying to access an element from a sequence (like a list or tuple) using an index that is out of range.
ValueErrorRaised when a function receives an argument of the correct type but an inappropriate value (e.g., trying to convert a non-numeric string into an integer).
TypeErrorRaised when an operation or function is applied to an object of an inappropriate type.
FileNotFoundErrorRaised when an attempt to open a file fails because the file does not exist at the specified location.
AttributeErrorRaised when an invalid attribute reference or assignment is made, such as calling a method that does not exist on an object.
KeyErrorRaised when trying to access a dictionary key that doesn't exist.
OverflowErrorRaised when the result of an arithmetic operation is too large to be represented.
MemoryErrorRaised when an operation runs out of memory.
ImportErrorRaised when an import statement fails to find the specified module.
StopIterationRaised when the `next()` function is called on an iterator that has no more items.
IndentationErrorRaised when there is incorrect indentation in the code.
UnicodeErrorRaised when there is a Unicode-related encoding or decoding error.
AssertionErrorRaised when an assert statement fails (i.e., a condition that must be true fails).
NotImplementedErrorRaised when an abstract method or function has not been implemented.
PermissionErrorRaised when trying to access a file or directory without sufficient permissions.
OSErrorRaised when a system function returns a system-related error, such as file system errors.

Exceptions in Python:

python

# Example 1: SyntaxError
# Raised when there is an issue with the syntax in the code.

print('Hello'  # Missing closing parenthesis
# Output: SyntaxError: unexpected EOF while parsing


# Example 2: ZeroDivisionError
# Raised when trying to divide a number by zero.

x = 1 / 0  # Division by zero
# Output: ZeroDivisionError: division by zero


# Example 3: NameError
# Raised when trying to access a variable that has not been defined.

print(x)  # 'x' is not defined
# Output: NameError: name 'x' is not defined


# Example 4: IndexError
# Raised when accessing an element with an index that is out of range.

my_list = [1, 2, 3]
print(my_list[5])  # Index out of range
# Output: IndexError: list index out of range


# Example 5: ValueError
# Raised when a function receives an argument of the correct type, but an inappropriate value.

int('abc')  # Cannot convert a non-numeric string to an integer
# Output: ValueError: invalid literal for int() with base 10: 'abc'


# Example 6: TypeError
# Raised when an operation or function is applied to an object of an inappropriate type.

result = 'hello' + 1  # Cannot concatenate a string and an integer
# Output: TypeError: can only concatenate str (not "int") to str


# Example 7: FileNotFoundError
# Raised when an attempt to open a file fails because the file does not exist.

open('non_existing_file.txt')  # File does not exist
# Output: FileNotFoundError: [Errno 2] No such file or directory: 'non_existing_file.txt'


# Example 8: AttributeError
# Raised when an invalid attribute reference or assignment is made.

'hello'.non_existing_method()  # 'str' object has no attribute 'non_existing_method'
# Output: AttributeError: 'str' object has no attribute 'non_existing_method'


# Example 9: KeyError
# Raised when trying to access a dictionary key that doesn't exist.

my_dict = {'a': 1}
print(my_dict['b'])  # Key 'b' does not exist
# Output: KeyError: 'b'


# Example 10: OverflowError
# Raised when the result of an arithmetic operation is too large to be represented.

x = 1e1000  # Exceeds the maximum size for a number
# Output: OverflowError: (varies depending on Python implementation)


# Example 11: MemoryError
# Raised when an operation runs out of memory.

a = [1] * (10**10)  # Trying to allocate too much memory
# Output: MemoryError: (varies depending on the system)


# Example 12: ImportError
# Raised when an import statement fails to find the specified module.

import non_existing_module  # Module does not exist
# Output: ImportError: No module named 'non_existing_module'


# Example 13: StopIteration
# Raised when the next() function is called on an iterator that has no more items.

my_iter = iter([])
next(my_iter)  # No more items to iterate
# Output: StopIteration


# Example 14: IndentationError
# Raised when there is incorrect indentation in the code.

def func():
print('Hello')  # IndentationError: expected an indented block
# Output: IndentationError: expected an indented block


# Example 15: UnicodeError
# Raised when there is a Unicode-related encoding or decoding error.

'hello'.encode('ascii')  # Can't encode to ASCII
# Output: UnicodeError: 'ascii' codec can't encode character


# Example 16: AssertionError
# Raised when an assert statement fails (i.e., a condition that must be true fails).

assert 1 == 2  # Assertion fails
# Output: AssertionError


# Example 17: NotImplementedError
# Raised when an abstract method or function has not been implemented.

class MyClass:
    def my_method(self):
        raise NotImplementedError

obj = MyClass()
obj.my_method()  # Method is not implemented
# Output: NotImplementedError


# Example 18: PermissionError
# Raised when trying to access a file or directory without sufficient permissions.

open('protected_file.txt')  # File is protected
# Output: PermissionError: [Errno 13] Permission denied: 'protected_file.txt'


# Example 19: OSError
# Raised when a system function returns a system-related error.

os.remove('file')  # File is in use or protected
# Output: OSError: [Errno 2] No such file or directory: 'file'


Frequently Asked Questions

What are errors and exceptions in Python?

Errors are issues that prevent a program from running, while exceptions are runtime issues that can be caught and handled to prevent crashes.


What is the difference between errors and exceptions in Python?

Errors usually prevent a program from running (like syntax errors), while exceptions can occur during runtime and can be handled using try-except blocks.


How do I handle exceptions in Python?

Use a try-except block. For example:try:
  # some code that may raise an exception
except Exception as e:
  # handle the exception


What is the purpose of the 'finally' block?

The 'finally' block is always executed, regardless of whether an exception occurred. It's useful for code that must run for cleanup, such as closing a file or releasing resources.


Can I create custom exceptions in Python?

Yes, you can create custom exceptions by subclassing Python’s built-in Exception class:
class MyCustomError(Exception):
  pass



What's Next?

In the next section, we will dive deeper into exception handling in Python. You’ll learn how to use the try-except blocks to handle errors, ensure your programs run smoothly, and prevent them from crashing unexpectedly.