Programs can fail while running: a user types text where a number was expected, a file is missing, or a value is divided by zero. Exception handling lets a program detect such errors, respond with a clear message and keep running. This chapter explains what exceptions are, the common built-in exceptions, and how to handle them with the try, except, else and finally blocks.
Read each section, then type out (don't copy-paste!) the code examples yourself. Read the 📋 Board Exam Tips alongside each section, and pay particular attention to Sections 4.4, 4.4.3 and 4.4.4 during revision.
4.1 Introduction
Picture this: You write a perfect program. It works beautifully in testing. You submit it. Then a user types "abc" where a number was expected — and your whole program CRASHES with a red scary error message. 😱
This is why every professional programmer learns Exception Handling — the art of expecting the unexpected!
Without Exception Handling
Program crashes the moment anything goes wrong
User sees a confusing traceback and loses all workWith Exception Handling
Errors are caught gracefully
User sees a helpful message; program continues or exits cleanlyWithout Handling: With Handling:
───────────────── ─────────────────
User enters "abc" User enters "abc"
↓ ↓
Program CRASHES 💥 Error CAUGHT 🎣
Traceback printed "Please enter a number!"
Program STOPS Program CONTINUES ✅
Think of exception handling like a safety net under a trapeze artist. The artist (your program) performs amazing moves (operations). If they slip (an error occurs), the safety net (exception handler) catches them — the show goes on!
4.2 Exceptions and Exception Handling
What is an Error?
In programming, things go wrong in three main ways. Knowing which type helps you fix it faster:
Syntax Error
Mistake in the grammar of Python code
primt("Hello") → typo — Python won't even startRuntime Error
Valid syntax, but something crashes during execution
10 / 0 → can't divide by zero while runningLogical Error
Program runs but gives wrong output
Adding instead of multiplying — hardest to find!What is an Exception?
An exception is a runtime error that occurs during the execution of a program and disrupts the normal flow of instructions.
When Python hits a problem at runtime, it raises (creates) an exception object. If nothing handles it, the program crashes with a traceback.
Normal Flow: Exception Occurs:
───────────── ──────────────────
statement 1 ✅ statement 1 ✅
statement 2 ✅ statement 2 ✅
statement 3 ✅ statement 3 💥 ← Exception raised here!
statement 4 ✅ ↓
statement 5 ✅ Program STOPS (if unhandled)
Code Example: exception_demo.py
# exception_demo.py
# What happens without exception handling?
num = int(input("Enter a number: ")) # User types "abc"
result = 100 / num
print(f"Result: {result}")
# If user types "abc":
# ValueError: invalid literal for int() with base 10: 'abc'
# If user types "0":
# ZeroDivisionError: division by zero
# Program crashes! ❌ Not professional at all.
"Define Exception." — 1 mark Answer: An exception is an event that occurs during the execution of a program that disrupts the normal flow of the program's instructions. It is a runtime error that Python represents as an object.
4.3 Concept of Exception Handling
Exception Handling is a mechanism that allows a program to detect and handle runtime errors gracefully — without crashing — so the program can either recover or exit cleanly.
The Big Idea: Separate "Try" from "Handle"
flowchart LR
TRY["TRY Block\nRisky Code"]
EXCEPT["EXCEPT Block\nHandle error"]
ELSE["ELSE Block\nIf no error"]
FINALLY["FINALLY Block\nAlways runs (Clean-up)"]
NEXT["Program Continues\nNo crashing!"]
TRY -->|"Error?"| EXCEPT
TRY -->|"No Error?"| ELSE
EXCEPT --> FINALLY
ELSE --> FINALLY
FINALLY --> NEXT
classDef tryNode fill:none;
classDef exceptNode fill:none;
classDef elseNode fill:none;
classDef normalNode fill:none;
class TRY tryNode;
class EXCEPT exceptNode;
class ELSE elseNode;
class FINALLY normalNode;
class NEXT normalNode;
Why is this powerful?
Prevents Crashes
Program survives bad input or missing files
ATM doesn't crash if you type wrong PINFriendly Messages
Show helpful errors instead of scary tracebacks
"File not found!" instead of FileNotFoundErrorProgram Continues
Handle and move on — don't lose all progress
Game doesn't quit on one wrong inputClean Cleanup
Always release resources (files, connections)
Files get closed even if errors occurException handling doesn't mean you write buggy code on purpose! Think of it as a second line of defence. Write clean code first. Add exception handling for things you can't control — user input, file operations, network calls, division operations.
4.4 Exception Handling in Python
Python provides a clean, readable syntax for exception handling using four keywords:
try → "Attempt this risky code"
except → "If that specific error occurs, do this"
else → "If NO error occurred, also do this"
finally → "Do this NO MATTER WHAT (error or not)"
Basic Syntax:
try:
# Risky code that might raise an exception
<statement(s)>
except ExceptionType:
# Code to handle the specific exception
<statement(s)>
else:
# Runs ONLY if no exception was raised in try
<statement(s)>
finally:
# Runs ALWAYS — error or no error
<statement(s)>
else and finally are optional. The minimum valid structure is just try + except.
Code Example: basic_try_except.py
# basic_try_except.py
# Your first exception handler!
try:
num = int(input("Enter a number: "))
result = 100 / num
print(f"100 ÷ {num} = {result}")
except ZeroDivisionError:
print("❌ Oops! Cannot divide by zero. Please enter a non-zero number.")
except ValueError:
print("❌ That's not a valid number! Please enter digits only.")
# If user enters 0:
# ❌ Oops! Cannot divide by zero. Please enter a non-zero number.
# If user enters "abc":
# ❌ That's not a valid number! Please enter digits only.
# If user enters 4:
# 100 ÷ 4 = 25.0 ← Works perfectly! ✅
"Write the syntax of try-except block in Python." — 2 marks.
Always include try: followed by the risky code, then except ExceptionType: with the handler. Indentation is mandatory!
4.4.1 General Built-in Python Exceptions
Python has a hierarchy of built-in exceptions. Here are the ones you need to know for the syllabus.
BaseException
└── Exception
├── ArithmeticError
│ └── ZeroDivisionError ← ÷ by zero
├── LookupError
│ ├── IndexError ← list[99] out of range
│ └── KeyError ← dict["missing_key"]
├── TypeError ← wrong data type
├── ValueError ← right type, wrong value
├── NameError ← variable not defined
├── FileNotFoundError ← file doesn't exist
├── ImportError ← module not found
├── AttributeError ← object has no such attribute
└── OverflowError ← number too large
Key Built-in Exceptions:
| Exception | When Does It Occur? | Example That Causes It |
|---|---|---|
ZeroDivisionError |
Dividing by zero | 10 / 0 |
ValueError |
Correct type, invalid value | int("abc") |
TypeError |
Wrong data type in operation | "2" + 2 |
NameError |
Variable used before assignment | print(xyz) (xyz undefined) |
IndexError |
List index out of range | lst[10] when list has 5 items |
KeyError |
Dictionary key doesn't exist | d["age"] when key absent |
FileNotFoundError |
File not found on disk | open("ghost.txt") |
ImportError |
Module doesn't exist | import unicorn |
AttributeError |
Object has no such attribute | "hello".push("!") |
OverflowError |
Numeric result too large | math.exp(1000) |
Code Example: exception_showcase.py
# exception_showcase.py
# See each exception in action!
# 1. ZeroDivisionError
try:
x = 10 / 0
except ZeroDivisionError:
print("ZeroDivisionError: Can't divide by zero!")
# 2. ValueError
try:
n = int("hello")
except ValueError:
print("ValueError: 'hello' cannot be converted to int!")
# 3. TypeError
try:
result = "5" + 5
except TypeError:
print("TypeError: Can't add string and integer!")
# 4. NameError
try:
print(undefined_var)
except NameError:
print("NameError: Variable not defined!")
# 5. IndexError
try:
lst = [1, 2, 3]
print(lst[10])
except IndexError:
print("IndexError: Index 10 doesn't exist in list of 3!")
# 6. KeyError
try:
d = {"name": "Arjun"}
print(d["age"])
except KeyError:
print("KeyError: 'age' key doesn't exist in dictionary!")
# 7. FileNotFoundError
try:
f = open("marks.txt")
except FileNotFoundError:
print("FileNotFoundError: marks.txt doesn't exist!")
"Name any four built-in exceptions in Python with one example each." — 4 marks (½ + ½ × 4 = 4). Always pair each exception name with the exact Python statement that triggers it. The table above is your cheat sheet!
"Zero Value Type Name Index" → ZeroDivisionError, ValueError, TypeError, NameError, IndexError
These are the five exceptions to learn first.
4.4.2 Second Argument of the except Block
You can capture the exception object using as keyword in the except clause. This gives you access to the actual error message Python generated — incredibly useful for debugging!
Syntax:
except ExceptionType as variable_name:
↑
This captures the exception object
Now you can print its message!
Code Example: except_as_demo.py
# except_as_demo.py
# Catching the exception message itself
try:
num = int(input("Enter a number: "))
result = 100 / num
print(f"Result: {result}")
except ZeroDivisionError as e:
print(f"❌ Math Error: {e}")
# Output: ❌ Math Error: division by zero
except ValueError as e:
print(f"❌ Input Error: {e}")
# Output: ❌ Input Error: invalid literal for int() with base 10: 'abc'
# 'e' is the exception object — str(e) gives its message!
Code Example: exception_info.py
# exception_info.py
# Getting more info from the exception object
try:
marks = [90, 85, 78]
print(marks[10]) # IndexError
except IndexError as err:
print(f"Error Type : {type(err).__name__}") # IndexError
print(f"Error Message : {err}") # list index out of range
print(f"Handled! Program continues... ✅")
# Output:
# Error Type : IndexError
# Error Message : list index out of range
# Handled! Program continues... ✅
"What is the use of as keyword in an except clause?" — 2 marks.
Answer: The as keyword in the except clause captures the exception object into a variable. This variable can then be used to access and display the actual error message generated by Python, which is helpful for debugging.
str(e) vs repr(e)str(e) gives a human-readable message: "division by zero"
repr(e) gives the full technical representation: "ZeroDivisionError('division by zero')"
For display to users, always use str(e) or just e in an f-string.
4.4.3 Handling Multiple Errors
Real programs can fail in multiple ways. Python lets you handle each type of error differently — or group them together.
Method 1: Multiple except Clauses (Most Common)
Write one except block for each exception type. Python checks them top to bottom and executes the FIRST matching one.
try:
risky code
except ExceptionType1:
handle error 1
except ExceptionType2:
handle error 2
except ExceptionType3:
handle error 3
Code Example: multiple_except.py
# multiple_except.py
def safe_divide(a, b):
"""Safely divides a by b with multiple error handlers"""
try:
a = int(a) # Might raise ValueError
b = int(b) # Might raise ValueError
result = a / b # Might raise ZeroDivisionError
return result
except ValueError as e:
print(f"❌ ValueError: {e}")
print(" → Please enter numbers only!")
return None
except ZeroDivisionError:
print("❌ ZeroDivisionError: Cannot divide by zero!")
print(" → Please enter a non-zero divisor!")
return None
except TypeError as e:
print(f"❌ TypeError: {e}")
return None
# Test cases
print(safe_divide(10, 2)) # 5.0 ✅
print(safe_divide(10, 0)) # ZeroDivisionError ✅
print(safe_divide("abc", 5)) # ValueError ✅
Method 2: Catching Multiple Exceptions in One except (Tuple Syntax)
When two or more exceptions need the same handling, list them as a tuple:
except (ZeroDivisionError, ValueError):
print("Either a zero division or bad value occurred!")
Code Example: tuple_except.py
# tuple_except.py
# Handle multiple exceptions the same way
def get_list_item(lst, index):
try:
index = int(index) # ValueError if index is "abc"
return lst[index] # IndexError if out of range
except (ValueError, IndexError) as e:
# Both errors handled identically
print(f"❌ Cannot access item: {e}")
return None
nums = [10, 20, 30, 40, 50]
print(get_list_item(nums, 2)) # 30 ✅
print(get_list_item(nums, "abc")) # ValueError caught ✅
print(get_list_item(nums, 99)) # IndexError caught ✅
Method 3: Bare except — Catch ALL Exceptions
A except clause without specifying any exception type catches every possible exception. Use this as a last resort!
Code Example: bare_except.py
# bare_except.py
# Catch-all handler
try:
x = int(input("Enter value: "))
result = 100 / x
print(f"Result: {result}")
except ZeroDivisionError:
print("Cannot divide by zero!") # Specific handler first
except ValueError:
print("Not a valid number!") # Specific handler second
except:
# This catches ANYTHING else that goes wrong
print("⚠️ An unexpected error occurred! Please contact support.")
except Cautiously!A bare except: hides bugs by catching everything — including keyboard interrupts (Ctrl+C), system exits, and programming errors you should fix. Always prefer specific exception types. Use bare except: only as a final safety net.
Method 4: Using the Base Class Exception
try:
risky_code()
except Exception as e:
print(f"Something went wrong: {e}")
This catches all non-system exceptions (anything that inherits from Exception). A cleaner alternative to bare except:.
Always put specific exceptions BEFORE general ones.
# ✅ Correct — specific first
except ZeroDivisionError: ...
except Exception: ...
# ❌ Wrong — general first blocks specific ones!
except Exception: ... # catches everything!
except ZeroDivisionError: ... # NEVER reached!
This is a typical error-spotting question.
The try-else Clause
Python's try block has an optional else — this runs only if the try block completed without any exception. Think of it as "the success path."
try:
risky code
except SomeError:
handle error
else:
# ← This runs ONLY if try succeeded (no exception)
success code here
Code Example: try_else.py
# try_else.py
# The else clause — for when everything goes right!
def divide_numbers():
try:
a = int(input("Dividend: "))
b = int(input("Divisor : "))
result = a / b
except ZeroDivisionError:
print("❌ Cannot divide by zero!")
except ValueError:
print("❌ Please enter integers only!")
else:
# Only reaches here if NO exception occurred
print(f"✅ Success! {a} ÷ {b} = {result:.2f}")
print(" (This only prints when everything worked!)")
divide_numbers()
# If b = 0: → "❌ Cannot divide by zero!" (else skipped)
# If a = "xyz": → "❌ Please enter integers only!" (else skipped)
# If a=10, b=4: → "✅ Success! 10 ÷ 4 = 2.50"
else instead of putting code in try?Putting success-only code in else (not in try) is cleaner and safer — you're explicitly saying "this code should only run if everything above worked." It also prevents accidentally catching errors from the success code itself.
Complete Exception Handling Flow:
┌──────────────────────────────────────────────────────────┐
│ COMPLETE FLOW │
│ │
│ try: │
│ <risky statements> │
│ ↓ No error? ↓ Error occurs? │
│ │
│ else: except Type1: │
│ <success code> <handler 1> │
│ except Type2: │
│ <handler 2> │
│ except: │
│ <catch-all> │
│ │
│ finally: ←────────────────────────────────────── │
│ <always runs — error or not> │
└──────────────────────────────────────────────────────────┘
"What is the role of else clause in a try-except block?" — 2 marks.
Answer: The else clause in a try-except block is executed only when no exception is raised in the try block. It is used to write code that should run only upon successful execution of the try block. It is not executed if an exception occurs.
4.4.4 The finally Block
The finally block is the guarantee of Python exception handling. It always executes — whether an exception occurred or not, whether it was handled or not. Nothing can stop it!
try:
<risky code>
except:
<error handler>
finally:
<ALWAYS runs — no matter what!>
- 📘 Scenario 1 (No Error)
try✅- ↓
except(skipped) - ↓
finally✅ RUNS - ↓ program continues
- 📗 Scenario 2 (Error Handled)
try💥- ↓
except✅ - ↓
finally✅ RUNS - ↓ program continues
- 📙 Scenario 3 (Unhandled Error)
try💥- ↓
except(doesn't match) - ↓
finally✅ RUNS — Still runs! - ↓ program crashes (after finally)
Code Example: finally_demo.py
# finally_demo.py
# finally ALWAYS runs!
def read_file(filename):
f = None
try:
print(f"📂 Opening {filename}...")
f = open(filename, 'r')
data = f.read()
print(f"📄 File contents:\n{data}")
except FileNotFoundError:
print(f"❌ File '{filename}' not found!")
except PermissionError:
print(f"❌ No permission to read '{filename}'!")
finally:
# This ALWAYS runs — ensures file is properly closed
if f:
f.close()
print("🔒 File closed safely. (finally block ran)")
else:
print("🔒 No file to close. (finally block still ran)")
# Test 1: File exists
read_file("grades.txt")
# 📂 Opening grades.txt...
# 📄 File contents: ...
# 🔒 File closed safely. (finally block ran)
# Test 2: File doesn't exist
read_file("ghost.txt")
# 📂 Opening ghost.txt...
# ❌ File 'ghost.txt' not found!
# 🔒 No file to close. (finally block still ran)
Code Example: finally_always_runs.py
# finally_always_runs.py
# Demonstrating finally in ALL scenarios
def demonstrate(value):
print(f"\n--- Testing with value: {value} ---")
try:
result = 10 / value
print(f"Result: {result}")
except ZeroDivisionError:
print("Caught: ZeroDivisionError")
finally:
print("★ finally block executed! ★")
demonstrate(2) # No error — finally still runs
demonstrate(0) # ZeroDivisionError — finally still runs
demonstrate("x") # TypeError (unhandled) — finally still runs, THEN program crashes
# Output:
# --- Testing with value: 2 ---
# Result: 5.0
# ★ finally block executed! ★
# --- Testing with value: 0 ---
# Caught: ZeroDivisionError
# ★ finally block executed! ★
# --- Testing with value: x ---
# ★ finally block executed! ★
# TypeError: unsupported operand type(s) for /: 'int' and 'str'
Real-World Use Cases for finally:
| Scenario | What finally Guarantees |
|---|---|
| File operations | File is always closed, even on error |
| Database connections | Connection is always closed, preventing leaks |
| Network sockets | Socket is always disconnected properly |
| Lock/mutex | Lock is always released, preventing deadlock |
| Temporary files | Temp files are always deleted |
"What is the purpose of finally block in exception handling?" — 2 marks.
Answer: The finally block in Python's exception handling is guaranteed to execute whether an exception is raised or not. It is typically used to perform cleanup operations such as closing files, releasing resources, or closing database connections, ensuring that these actions are always performed regardless of whether an error occurred.
finally with returnIf both try and finally have return statements, finally's return overrides the try block's return. This is a tricky board question!
def tricky():
try:
return "from try"
finally:
return "from finally" # This wins!
print(tricky()) # "from finally"4.4.5 Raising Exceptions — The raise Statement
So far, Python raised exceptions for us. But YOU can also manually raise an exception using the raise keyword! This is used to enforce rules in your own functions.
Syntax:
raise ExceptionType("Your custom error message")
Code Example: raise_demo.py
# raise_demo.py
# Raising exceptions manually
def set_age(age):
"""Sets age — raises exception if invalid"""
if type(age) != int:
raise TypeError("Age must be an integer!")
if age < 0:
raise ValueError("Age cannot be negative!")
if age > 150:
raise ValueError(f"Age {age} is unrealistically large!")
print(f"✅ Age set to: {age}")
# Valid call
set_age(17) # ✅ Age set to: 17
# Invalid calls — exceptions raised manually
try:
set_age(-5)
except ValueError as e:
print(f"❌ ValueError: {e}") # Age cannot be negative!
try:
set_age(200)
except ValueError as e:
print(f"❌ ValueError: {e}") # Age 200 is unrealistically large!
try:
set_age("seventeen")
except TypeError as e:
print(f"❌ TypeError: {e}") # Age must be an integer!
Code Example: raise_in_function.py
# raise_in_function.py
# Using raise to enforce business rules
def calculate_discount(price, discount_percent):
"""Calculates discounted price with validation"""
if price < 0:
raise ValueError("Price cannot be negative!")
if not (0 <= discount_percent <= 100):
raise ValueError("Discount must be between 0 and 100!")
discounted = price * (1 - discount_percent / 100)
return round(discounted, 2)
# Safe calls with exception handling
try:
print(calculate_discount(1000, 20)) # ✅ 800.0
print(calculate_discount(-500, 10)) # ❌ ValueError
except ValueError as e:
print(f"Invalid input: {e}")
try:
print(calculate_discount(500, 110)) # ❌ ValueError
except ValueError as e:
print(f"Invalid input: {e}")
re-raise — Re-Raising a Caught Exception
You can re-raise an exception you caught (to log it and then let it propagate) using bare raise:
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Logging error: {e}") # Log it first
raise # Then re-raise — let it crash!
"What is the use of raise statement in Python?" — 2 marks.
Answer: The raise statement in Python is used to manually raise (trigger) an exception. It allows a programmer to enforce custom validation rules and generate meaningful error messages by raising built-in exceptions (like ValueError, TypeError) with custom error messages when input conditions are not met.
⚙️ Putting It All Together — Complete Exception Handling Structure
Code Example: complete_handler.py
# complete_handler.py
# Full try-except-else-finally in one real program
def student_grade_calculator():
"""Calculates student grade from marks input"""
print("=" * 40)
print(" STUDENT GRADE CALCULATOR")
print("=" * 40)
try:
name = input("Student Name : ")
marks = float(input("Marks (0-100): "))
# Manual raise for business rule
if not (0 <= marks <= 100):
raise ValueError(f"Marks must be 0-100, got {marks}")
# Grade calculation
if marks >= 90: grade = 'A+'
elif marks >= 80: grade = 'A'
elif marks >= 70: grade = 'B+'
elif marks >= 60: grade = 'B'
elif marks >= 33: grade = 'C'
else: grade = 'FAIL'
except ValueError as e:
print(f"\n❌ Invalid Input: {e}")
print(" Please run the program again.")
grade = None
except KeyboardInterrupt:
print("\n\n⚠️ Program interrupted by user!")
grade = None
else:
# Only runs if try succeeded completely
print(f"\n✅ Result for {name}:")
print(f" Marks : {marks}")
print(f" Grade : {grade}")
finally:
# ALWAYS runs
print("\n" + "=" * 40)
print(" Thank you for using Grade Calculator!")
print("=" * 40)
student_grade_calculator()
⚠️ Common Errors and Exception Handling Mistakes
| Mistake | Wrong Code ❌ | Correct Code ✅ | Explanation |
|---|---|---|---|
| General before specific | except Exception: then except ValueError: |
Specific first | ValueError never reached |
| Swallowing exceptions silently | except: pass |
except Exception as e: print(e) |
Silent failures are hard to debug |
Using bare except everywhere |
except: for everything |
Use specific types | Hides bugs and system signals |
No finally for resources |
File opened, no close | Always use finally or with |
Resource leak! |
raise without message |
raise ValueError |
raise ValueError("Reason!") |
Always explain WHY |
Forgetting global in handler |
Modifying global var | Use global keyword |
UnboundLocalError |
The Four Keywords:
try→ Put risky code hereexcept→ Handle specific errors hereelse→ Runs only when try succeeds (no error)finally→ Runs ALWAYS (cleanup code here)
Exception Hierarchy — Key Points:
| Exception | Trigger |
|---|---|
ZeroDivisionError |
x / 0 |
ValueError |
int("abc") |
TypeError |
"a" + 1 |
NameError |
print(undefined) |
IndexError |
lst[100] on short list |
KeyError |
dict["missing"] |
FileNotFoundError |
open("nope.txt") |
as keyword: except ValueError as e: → captures the error object; print(e) shows its message.
Multiple Exceptions:
except (TypeError, ValueError): # Same handler for both
except TypeError: ...
except ValueError: ... # Different handlers
except Exception as e: ... # Catch-all (use carefully)
raise keyword: Manually trigger exceptions to enforce your own rules.
raise ValueError("Age must be positive!")
finally Rule: Always runs. Use for cleanup (close files, connections, etc.)
🎯 Sample Board Exam Questions
Q1: What will be the output? [2 marks]
try:
a = 10
b = 0
c = a / b
print(c)
except ZeroDivisionError:
print("Cannot divide by zero")
except:
print("Some other error")
finally:
print("Always executed")
Answer:
Cannot divide by zero
Always executed
Q2: Find the error and correct it. [2 marks]
try:
n = int(input("Enter: "))
result = 10 / n
except Exception:
print("General error")
except ZeroDivisionError:
print("Division by zero")
Error: SyntaxError — except Exception (general) is placed before except ZeroDivisionError (specific). The specific handler will never be reached.
Corrected:
try:
n = int(input("Enter: "))
result = 10 / n
except ZeroDivisionError:
print("Division by zero")
except Exception:
print("General error")
Q3: What will be the output? [3 marks]
def divide(a, b):
try:
result = a / b
except ZeroDivisionError:
print("Error: division by zero")
return -1
else:
print("Division successful")
return result
finally:
print("Execution complete")
print(divide(10, 2))
print(divide(10, 0))
Answer:
Division successful
Execution complete
5.0
Error: division by zero
Execution complete
-1
(Note: finally runs before the return value is actually returned.)
Q4: Write a program. [3 marks]
Write a Python program that asks the user for two numbers and divides them. Handle ZeroDivisionError, ValueError, and any other exception. Use finally to print "Operation Complete."
try:
a = float(input("Enter dividend: "))
b = float(input("Enter divisor : "))
result = a / b
except ZeroDivisionError:
print("❌ Error: Cannot divide by zero!")
except ValueError:
print("❌ Error: Please enter numeric values only!")
except Exception as e:
print(f"❌ Unexpected error: {e}")
else:
print(f"✅ Result: {a} ÷ {b} = {result:.4f}")
finally:
print("\nOperation Complete.")
Q5: Predict the output — tricky! [2 marks]
try:
lst = [1, 2, 3]
print(lst[1])
print(lst[5])
print("Done")
except IndexError as e:
print(f"Caught: {e}")
else:
print("No errors!")
finally:
print("Finally!")
Answer:
2
Caught: list index out of range
Finally!
Explanation:
lst[1]→ prints2✅lst[5]→ raisesIndexError→ jumps toexcept"Done"is never reached (exception interrupted try)elseis skipped (because an exception occurred)finallyalways runs ✅
Q6: What is the output? [2 marks]
def check(n):
if n < 0:
raise ValueError("Negative not allowed!")
return n * 2
try:
print(check(5))
print(check(-3))
print(check(10))
except ValueError as e:
print(f"Handled: {e}")
Answer:
10
Handled: Negative not allowed!
(After check(-3) raises ValueError, execution jumps to except — check(10) never runs.)
Practice Problems
Strengthen your skills with these exercises:
-
Write a program that accepts a list from the user and a position. Print the element at that position, handling
IndexErrorandValueErrorappropriately. -
Write a function
safe_open(filename)that opens a text file, reads and prints its contents, and usesfinallyto always close the file. HandleFileNotFoundError. -
Write a function
validate_marks(marks)that usesraiseto enforce: marks must be int, between 0 and 100. Test it with try-except. -
Write a program that demonstrates
try-except-else-finallywith all four parts executing at least once (show two runs: one with error, one without). -
What is the output of the following code? Explain each line.
for i in [2, 0, "x", 5]: try: print(10 / int(i)) except ZeroDivisionError: print("Zero!") except (ValueError, TypeError): print("Bad value!") -
Write a program that keeps asking the user for a positive integer until they provide one. Use a
while Trueloop withtry-exceptto handle bad inputs gracefully. -
Create a dictionary with 3 student names and marks. Write a program that lets the user look up marks by name, handling
KeyErrorif the name is not found. -
Write a function
convert_to_int(value)that usesraiseandexceptto validate thatvalueis convertible to an integer, returning the converted value or a helpful error message.