Lesson 13 of 2011 min read
Exception Handling in Python
Prerequisites: Functions, basic Python syntax
1. Syntax Errors vs Exceptions
Syntax Errors (Parsing Errors)
Detected before the program runs. The code cannot execute at all.
# Syntax Error - missing colon
if True
print("Hello")
# SyntaxError: expected ':'
# Syntax Error - mismatched parentheses
print("Hello"
# SyntaxError: unexpected EOF while parsing
Exceptions (Runtime Errors)
Detected during execution. The code is syntactically correct but fails while running.
# Exception - division by zero
x = 10 / 0
# ZeroDivisionError: division by zero
# Exception - accessing invalid index
L = [1, 2, 3]
print(L[5])
# IndexError: list index out of range
Key difference: Syntax errors are caught by the interpreter before running; exceptions occur while the program is running.
2. Built-in Exceptions
| Exception | When It Occurs | Example |
|---|---|---|
SyntaxError |
Invalid Python syntax | if True print |
ValueError |
Right type but inappropriate value | int("abc") |
IOError |
File operation failure (legacy, now OSError) |
open("nonexistent.txt") |
KeyboardInterrupt |
User presses Ctrl+C | Interrupting input |
ImportError |
Module not found | import nonexistent_module |
EOFError |
input hits end-of-file |
Ctrl+D during input |
ZeroDivisionError |
Division or modulo by zero | 10 / 0 |
IndexError |
Sequence index out of range | [1,2][5] |
NameError |
Variable not defined | print(x) when x is undefined |
IndentationError |
Incorrect indentation | Missing indent after if: |
TypeError |
Operation on incompatible types | "2" + 2 |
OverflowError |
Result too large to represent | math.exp(1000) |
Examples of Each
# 1. SyntaxError
# eval("if True print")
# SyntaxError: invalid syntax
# 2. ValueError
# int("hello")
# ValueError: invalid literal for int with base 10: 'hello'
# 3. IOError / OSError
# f = open("nonexistent_file.txt", "r")
# FileNotFoundError: [Errno 2] No such file or directory
# 4. KeyboardInterrupt
# (Press Ctrl+C during execution)
# name = input("Enter name: ") # then press Ctrl+C
# KeyboardInterrupt
# 5. ImportError
# import nonexistent_module
# ModuleNotFoundError: No module named 'nonexistent_module'
# 6. EOFError
# (Press Ctrl+D during input on Linux/Mac, Ctrl+Z on Windows)
# x = input("Enter: ")
# EOFError: EOF when reading a line
# 7. ZeroDivisionError
# result = 10 / 0
# ZeroDivisionError: division by zero
# 8. IndexError
# L = [10, 20, 30]
# print(L[10])
# IndexError: list index out of range
# 9. NameError
# print(undefined_variable)
# NameError: name 'undefined_variable' is not defined
# 10. IndentationError
# if True:
# print("Hello")
# IndentationError: expected an indented block
# 11. TypeError
# result = "5" + 3
# TypeError: can only concatenate str (not "int") to str
# 12. OverflowError
# import math
# math.exp(1000)
# OverflowError: math range error
3. The raise Statement
Used to deliberately throw an exception.
Syntax
raise ExceptionType("message")
Examples
# Example 1: Raise ValueError for invalid age
age = int(input("Enter age: "))
if age < 0:
raise ValueError("Age cannot be negative!")
print("Age is:", age)
# Input: -5
# Output: ValueError: Age cannot be negative!
# Example 2: Raise TypeError
def add_numbers(a, b):
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
raise TypeError("Both arguments must be numbers")
return a + b
print(add_numbers(5, 3)) # Output: 8
# print(add_numbers("5", 3)) # TypeError: Both arguments must be numbers
# Example 3: Raise with custom condition
def set_marks(marks):
if marks < 0 or marks > 100:
raise ValueError("Marks must be between 0 and 100")
print("Marks set to:", marks)
set_marks(85) # Output: Marks set to: 85
# set_marks(150) # ValueError: Marks must be between 0 and 100
# Example 4: Re-raise an exception
def divide(a, b):
try:
result = a / b
except ZeroDivisionError:
print("Caught division by zero!")
raise # Re-raises the same exception
return result
# divide(10, 0)
# Output: Caught division by zero!
# Then: ZeroDivisionError: division by zero
4. The assert Statement
Used for debugging - tests a condition, raises AssertionError if False.
Syntax
assert condition, "optional error message"
Examples
# Example 1: Basic assert
x = 10
assert x > 0, "x must be positive"
print("x is:", x)
# Output: x is: 10
y = -5
# assert y > 0, "y must be positive"
# AssertionError: y must be positive
# Example 2: Assert for function input
def calculate_average(marks):
assert len(marks) > 0, "List cannot be empty"
return sum(marks) / len(marks)
print(calculate_average([80, 90, 70])) # Output: 80.0
# print(calculate_average([])) # AssertionError: List cannot be empty
# Example 3: Assert for type checking
def greet(name):
assert isinstance(name, str), "Name must be a string"
print("Hello,", name)
greet("Rahul") # Output: Hello, Rahul
# greet(123) # AssertionError: Name must be a string
# Example 4: Assert for range validation
def set_percentage(p):
assert 0 <= p <= 100, "Percentage must be between 0 and 100"
print("Percentage:", p)
set_percentage(85) # Output: Percentage: 85
# set_percentage(110) # AssertionError: Percentage must be between 0 and 100
5. try-except Block
Single except
try:
x = int(input("Enter a number: "))
print("You entered:", x)
except ValueError:
print("Invalid input! Please enter a number.")
# Input: abc
# Output: Invalid input! Please enter a number.
Multiple except Blocks
try:
a = int(input("Enter numerator: "))
b = int(input("Enter denominator: "))
result = a / b
print("Result:", result)
except ValueError:
print("Error: Please enter valid integers.")
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
# Input: 10, 0
# Output: Error: Cannot divide by zero.
# Input: abc, 5
# Output: Error: Please enter valid integers.
Multiple Exceptions in One except
try:
L = [10, 20, 30]
index = int(input("Enter index: "))
print("Value:", L[index])
except (ValueError, IndexError) as e:
print("Error occurred:", e)
# Input: abc
# Output: Error occurred: invalid literal for int with base 10: 'abc'
# Input: 10
# Output: Error occurred: list index out of range
Generic except (Catches All Exceptions)
try:
x = int(input("Enter number: "))
result = 100 / x
print("Result:", result)
except:
print("Some error occurred!")
# Catches ANY exception - use sparingly, as it hides specific errors
except with Exception class (Better Practice)
try:
x = int(input("Enter number: "))
result = 100 / x
print("Result:", result)
except Exception as e:
print("Error:", type(e).__name__, "-", e)
# Input: 0
# Output: Error: ZeroDivisionError - division by zero
6. try-except-else
The else block runs only if no exception occurs in the try block.
try:
num = int(input("Enter a number: "))
result = 100 / num
except ValueError:
print("Invalid input!")
except ZeroDivisionError:
print("Cannot divide by zero!")
else:
print("Result is:", result) # Runs only if try succeeds
# Input: 5
# Output: Result is: 20.0
# Input: 0
# Output: Cannot divide by zero!
7. try-except-else-finally
The finally block always executes, whether an exception occurs or not.
try:
num = int(input("Enter a number: "))
result = 100 / num
except ValueError:
print("Invalid input!")
except ZeroDivisionError:
print("Cannot divide by zero!")
else:
print("Result is:", result)
finally:
print("--- Execution complete ---") # ALWAYS runs
# Input: 5
# Output:
# Result is: 20.0
# --- Execution complete ---
# Input: 0
# Output:
# Cannot divide by zero!
# --- Execution complete ---
# Input: abc
# Output:
# Invalid input!
# --- Execution complete ---
8. finally Always Executes (Even with Unhandled Exceptions)
# Example: finally runs even when exception is NOT caught
try:
x = 10 / 0 # ZeroDivisionError - not caught below
except ValueError:
print("ValueError caught")
finally:
print("Finally block executed!")
# Output:
# Finally block executed!
# Traceback (most recent call last):
# ...
# ZeroDivisionError: division by zero
# NOTE: finally ran BEFORE the traceback terminates the program
# Example: finally runs even with return statement
def test:
try:
return 1
finally:
print("Finally in function!")
result = test
print("Returned:", result)
# Output:
# Finally in function!
# Returned: 1
Practice Programs
Program 1: Division with ZeroDivisionError Handling
# Program to divide two numbers with error handling
def divide:
try:
num1 = float(input("Enter numerator: "))
num2 = float(input("Enter denominator: "))
result = num1 / num2
except ZeroDivisionError:
print("Error: Division by zero is not allowed!")
except ValueError:
print("Error: Please enter valid numbers!")
else:
print(f"{num1} / {num2} = {result}")
divide
# Test Run 1:
# Enter numerator: 10
# Enter denominator: 3
# 10.0 / 3.0 = 3.3333333333333335
# Test Run 2:
# Enter numerator: 10
# Enter denominator: 0
# Error: Division by zero is not allowed!
# Test Run 3:
# Enter numerator: abc
# Error: Please enter valid numbers!
Program 2: Input Validation with ValueError
# Program to take valid integer input using loop and exception handling
def get_valid_integer(prompt):
while True:
try:
value = int(input(prompt))
return value
except ValueError:
print("Invalid input! Please enter an integer.")
age = get_valid_integer("Enter your age: ")
print("Your age is:", age)
# Test Run:
# Enter your age: abc
# Invalid input! Please enter an integer.
# Enter your age: 12.5
# Invalid input! Please enter an integer.
# Enter your age: 16
# Your age is: 16
Program 3: Multiple Exception Handling in One Program
# Program demonstrating multiple exception types
def process_data:
data = [10, 20, 30, 40, 50]
try:
index = int(input("Enter index (0-4): "))
value = data[index]
divisor = int(input("Enter divisor: "))
result = value / divisor
print(f"data[{index}] / {divisor} = {result}")
except ValueError:
print("Error: Please enter a valid integer!")
except IndexError:
print(f"Error: Index must be between 0 and {len(data)-1}!")
except ZeroDivisionError:
print("Error: Cannot divide by zero!")
except Exception as e:
print(f"Unexpected error: {e}")
else:
print("Operation completed successfully.")
finally:
print("Thank you for using the program.")
process_data
# Test Run 1:
# Enter index (0-4): 2
# Enter divisor: 5
# data[2] / 5 = 6.0
# Operation completed successfully.
# Thank you for using the program.
# Test Run 2:
# Enter index (0-4): 10
# Error: Index must be between 0 and 4!
# Thank you for using the program.
# Test Run 3:
# Enter index (0-4): 1
# Enter divisor: 0
# Error: Cannot divide by zero!
# Thank you for using the program.
Program 4: Using assert for Input Validation
# Program using assert to validate marks
def calculate_grade(marks):
assert isinstance(marks, (int, float)), "Marks must be a number"
assert 0 <= marks <= 100, "Marks must be between 0 and 100"
if marks >= 90:
return "A+"
elif marks >= 80:
return "A"
elif marks >= 70:
return "B"
elif marks >= 60:
return "C"
elif marks >= 33:
return "D"
else:
return "Fail"
# Test cases
try:
print("Grade for 95:", calculate_grade(95)) # A+
print("Grade for 72:", calculate_grade(72)) # B
print("Grade for 25:", calculate_grade(25)) # Fail
print("Grade for 110:", calculate_grade(110)) # AssertionError
except AssertionError as e:
print("Assertion failed:", e)
# Output:
# Grade for 95: A+
# Grade for 72: B
# Grade for 25: Fail
# Assertion failed: Marks must be between 0 and 100
Program 5: File Operation with Exception Handling
# Program to read a file with complete error handling
def read_file(filename):
try:
f = open(filename, "r")
content = f.read
print("File contents:")
print(content)
except FileNotFoundError:
print(f"Error: File '{filename}' not found!")
except PermissionError:
print(f"Error: No permission to read '{filename}'!")
except IOError as e:
print(f"Error reading file: {e}")
else:
print(f"\nFile '{filename}' read successfully.")
print(f"Total characters: {len(content)}")
finally:
try:
f.close
print("File closed.")
except NameError:
print("File was never opened.")
# Test Run 1 (file exists):
read_file("sample.txt")
# Output (if file exists):
# File contents:
# Hello World
# This is a test file.
#
# File 'sample.txt' read successfully.
# Total characters: 32
# File closed.
# Test Run 2 (file doesn't exist):
read_file("nonexistent.txt")
# Output:
# Error: File 'nonexistent.txt' not found!
# File was never opened.
Common Mistakes
| Mistake | Correct Approach |
|---|---|
Using bare except: everywhere |
Use specific exception types: except ValueError: |
Putting too much code in try block |
Keep try block minimal, only the risky lines |
Catching Exception and ignoring it |
Always print or log the error message |
Confusing except and else |
except = error happened; else = no error happened |
Using assert for user input validation |
Use assert for debugging; use if-raise for user input |
Forgetting that finally always runs |
finally runs even if exception is unhandled |
$1$2 Quick Tips
- Predict output questions: Trace through try-except-else-finally carefully. Remember
elseruns only when no exception occurs, andfinallyalways runs. - Know the exception types: Be able to identify which exception a given code snippet will raise.
- Difference questions: Syntax error vs Exception,
raisevsassert,try-exceptvstry-except-finally. - Code writing: Practice writing try-except blocks for file handling and numeric input.
- Remember:
assertraisesAssertionError, notAssertError. - finally block: Even if there is a
returnin thetryblock,finallystill executes.
Prefer watching over reading?
Subscribe for free.