Understanding Exceptions

Learn what exceptions are, common built-in exceptions in Python, and how they differ from syntax errors.

Understanding Exceptions

Exceptions are errors that occur during program execution (runtime errors). Unlike syntax errors, which are detected before the program runs, exceptions occur when the program is running and encounters an unexpected situation.

What are Exceptions?

An exception is an event that disrupts the normal flow of a program’s execution. When an exception occurs, Python creates an exception object that contains information about what went wrong.

Exceptions vs Syntax Errors

Syntax Errors: These are detected by Python before the program runs. They occur when the code doesn’t follow Python’s syntax rules.

syntax-error.py
# Syntax Error - missing colon
def greet(name)
print(f"Hello, {name}!")

Exceptions: These occur during program execution when something goes wrong, even though the syntax is correct.

exception-example.py
# This code has correct syntax but will raise an exception
x = 10 / 0 # ZeroDivisionError

Common Built-in Exceptions

Python provides many built-in exception types. Here are some of the most common ones:

ZeroDivisionError

Raised when attempting to divide by zero:

zero-division.py
result = 10 / 0 # ZeroDivisionError: division by zero

ValueError

Raised when a function receives an argument of the correct type but with an inappropriate value:

value-error.py
x = int("abc") # ValueError: invalid literal for int() with base 10: 'abc'

TypeError

Raised when an operation or function is applied to an object of inappropriate type:

type-error.py
result = "hello" + 5 # TypeError: can only concatenate str (not "int") to str

IndexError

Raised when trying to access an index that doesn’t exist in a sequence:

index-error.py
my_list = [1, 2, 3]
print(my_list[5]) # IndexError: list index out of range

KeyError

Raised when trying to access a dictionary key that doesn’t exist:

key-error.py
my_dict = {"name": "Alice", "age": 30}
print(my_dict["city"]) # KeyError: 'city'

AttributeError

Raised when trying to access an attribute or method that doesn’t exist:

attribute-error.py
my_list = [1, 2, 3]
my_list.appendd(4) # AttributeError: 'list' object has no attribute 'appendd'

FileNotFoundError

Raised when trying to open a file that doesn’t exist:

file-not-found.py
with open("nonexistent.txt", "r") as f:
content = f.read() # FileNotFoundError: [Errno 2] No such file or directory: 'nonexistent.txt'

Exception Hierarchy

All exceptions in Python inherit from the BaseException class. The most common base class for user-defined exceptions is Exception, which itself inherits from BaseException.

BaseException
├── Exception
│ ├── ArithmeticError
│ │ └── ZeroDivisionError
│ ├── LookupError
│ │ ├── IndexError
│ │ └── KeyError
│ ├── ValueError
│ ├── TypeError
│ └── ...
└── ...

Why Handle Exceptions?

Handling exceptions allows your program to:

  1. Continue running even when errors occur
  2. Provide meaningful error messages to users
  3. Clean up resources (close files, connections, etc.)
  4. Log errors for debugging
  5. Gracefully degrade functionality when something goes wrong

Exercises

Exercise 1: Identify Exception Types

Write code that demonstrates each of the following exceptions: ZeroDivisionError, ValueError, TypeError, IndexError, and KeyError. For each exception, print a message indicating which exception occurred.

Identify Exception Types

Checks: 0 times
Answer:
# ZeroDivisionError
try:
result = 10 / 0
except ZeroDivisionError:
print("ZeroDivisionError occurred")
# ValueError
try:
x = int("abc")
except ValueError:
print("ValueError occurred")
# TypeError
try:
result = "hello" + 5
except TypeError:
print("TypeError occurred")
# IndexError
try:
my_list = [1, 2, 3]
print(my_list[5])
except IndexError:
print("IndexError occurred")
# KeyError
try:
my_dict = {"name": "Alice"}
print(my_dict["age"])
except KeyError:
print("KeyError occurred")

Exercise 2: Safe List Access

Write a function safe_get_item that takes a list and an index. If the index is valid, return the item at that index. If the index is out of range, return None instead of raising an IndexError. Read the list size, then the list elements, then the index to access.

Safe List Access

Checks: 0 times
Answer:
def safe_get_item(my_list, index):
try:
return my_list[index]
except IndexError:
return None
n = int(input())
my_list = []
for i in range(n):
my_list.append(int(input()))
index = int(input())
result = safe_get_item(my_list, index)
print(result)

Course Progress

Section 46 of 61

Back to Course