Lesson 13 of 2011 min read

Exception Handling in Python

Share:WhatsAppLinkedIn

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

  1. Predict output questions: Trace through try-except-else-finally carefully. Remember else runs only when no exception occurs, and finally always runs.
  2. Know the exception types: Be able to identify which exception a given code snippet will raise.
  3. Difference questions: Syntax error vs Exception, raise vs assert, try-except vs try-except-finally.
  4. Code writing: Practice writing try-except blocks for file handling and numeric input.
  5. Remember: assert raises AssertionError, not AssertError.
  6. finally block: Even if there is a return in the try block, finally still executes.

Test Your Knowledge

Take a quick quiz on this lesson

Start Quiz →

Prefer watching over reading?

Subscribe for free.

Subscribe on YouTube