VM-LEARNING /class.xii ·track.cs ·ch-1-3 session: 2026_27
$cd ..

~/Exception Handling

root@vm-learning ~ $ open ch-1-3
UNIT 1 ▪ CHAPTER 3
03
Exception Handling
try · except · else · finally · raise · Custom Error Messages · Worked Programs
Exception handling is a mechanism that lets your program catch an error at the moment it happens and decide what to do next — instead of crashing. Python provides four keywords for this: try, except, else and finally.
Real-life analogy. Imagine you are making tea. The recipe works only if milk is available. Without exception handling, you would walk to the stove, find no milk, and panic. With exception handling, your brain has a back-up plan: “try the fridge; if there is no milk, use milk-powder; whichever happens, switch the stove off in the end.” try is what you attempt first, except is the back-up plan, and finally is the clean-up that must always happen.

3.1 Why do we need Exception Handling?

Real programs run in the real world — users type wrong inputs, files disappear, networks fail, division by zero happens. If any of these occur, Python stops the program and shows an angry red traceback. That is fine for a programmer debugging at home, but it is terrible for an end-user who just wanted to enter their marks.

n = int(input("Enter a number: ")) # user types "abc" print(100 / n)
ValueError: invalid literal for int() with base 10: 'abc' Process exited with code 1.

That one mistake crashed the whole program. Compare the same code with exception handling:

try: n = int(input("Enter a number: ")) # user types "abc" print(100 / n) except ValueError: print("Please enter a valid whole number.") except ZeroDivisionError: print("Number cannot be zero.")
Please enter a valid whole number.

The program still warned the user, but it did not crash. That is the power of exception handling.

Four big benefits:
  • Programs become robust — they survive bad input.
  • Error messages can be friendly (no scary traceback).
  • Clean-up work (closing files, disconnecting from the database) always runs.
  • Error-handling code is separated from normal code — easier to read.

3.2 Recap — Errors vs Exceptions

You met this in Class XI (§6 of the revision chapter). Here is the short version you need for this chapter.

Syntax errorException (run-time error)
When it happensBefore the program startsWhile the program is running
Exampleprin("hi")1 / 0ZeroDivisionError
Can you catch it?No — fix the codeYes — use try/except
Only exceptions can be handled with try/except. Syntax errors must be corrected by you before the program will even run.

3.2.1 Common built-in exceptions you will meet

ExceptionTriggered when…
ZeroDivisionErrorDivide or mod by zero
ValueErrorRight type, wrong value — int("abc")
TypeErrorWrong type — "x" + 2
NameErrorVariable not defined
IndexErrorList index out of range
KeyErrorMissing dictionary key
FileNotFoundErrorOpening a file that doesn’t exist
IOError / OSErrorGeneral input/output failure
AttributeErrorUsing a method/attribute the object doesn’t have
ImportError / ModuleNotFoundErrorimport something_missing

3.3 The try … except Block

3.3.1 The basic syntax

try: # risky code — might raise an exception ... except ExceptionType: # what to do if that exception is raised ...

Python executes the try block. If an exception occurs, Python jumps straight to the matching except block. If no exception occurs, the except block is skipped.

try: a = int(input("a: ")) b = int(input("b: ")) print("a/b =", a / b) except ZeroDivisionError: print("Error: cannot divide by zero.") except ValueError: print("Error: please enter whole numbers only.")
a: 10 b: 0 Error: cannot divide by zero.

3.3.2 Catching a specific exception — always preferred

Each except should name the specific exception it handles. This way, a different kind of bug is not accidentally swallowed and hidden.

3.3.3 Catching multiple exceptions in one block

If the response is the same for several exceptions, group them in a tuple:

try: n = int(input("n: ")) print(100 / n) except (ValueError, ZeroDivisionError): print("Bad input — try again.")

3.3.4 A generic except (use sparingly)

Writing except: or except Exception: catches every exception. This is a last resort — use it only when you genuinely don’t know which exception can occur.

try: risky_work() except Exception as e: print("Something went wrong:", e)
Avoid a bare except: — it will even swallow KeyboardInterrupt (Ctrl-C) and SystemExit, making your program impossible to stop. Always catch Exception instead, or a more specific type.

3.3.5 Getting the error message — as e

Use as variable after the exception name to capture the exception object. You can then read its message with str(e) or just print it.

try: n = int("abc") except ValueError as e: print("Details :", e) print("Type :", type(e).__name__)
Details : invalid literal for int() with base 10: 'abc' Type : ValueError

3.4 The else Clause

An optional block that runs only if no exception was raised in the try block. Useful when you want to keep the try block tiny and put the “success path” in else.

try: n = int(input("Enter a number: ")) except ValueError: print("That was not a number.") else: print("You entered", n) print("Its square is", n * n)
Enter a number: 7 You entered 7 Its square is 49
Why use else? It keeps the risky line alone in the try. If we had put print(n*n) inside try and n*n happened to raise some other error, the except ValueError would wrongly be blamed.

3.5 The finally Clause

An optional block that runs no matter what — whether the try succeeded, an exception was caught, or an exception was re-raised. Perfect for clean-up work like closing a file or a database connection.

try: f = open("marks.txt", "r") data = f.read() print(data) except FileNotFoundError: print("File does not exist.") finally: print("Closing file (clean-up).") try: f.close() except: pass # if the file never opened
finally is guaranteed to run — even if the try contains return, break or a raise. Use it for actions that must happen before the program moves on.

3.6 The Complete try / except / else / finally Flow

How Python chooses what to run: try block runs Exception? else block runs (no error) except block runs (handle the error) finally block runs (always — clean-up) No Yes

3.6.1 One-shot example combining all four

def read_number(): try: n = int(input("Enter a number: ")) except ValueError: print("Not a valid number.") n = 0 else: print("Got it — the number was", n) finally: print("(done reading)") return n read_number()
Enter a number: 9 Got it — the number was 9 (done reading) Enter a number: abc Not a valid number. (done reading)

3.7 The raise Statement

raise is how you can throw an exception on purpose. Use it when your function detects an invalid situation that its caller ought to handle.

3.7.1 Raising a built-in exception

def withdraw(balance, amount): if amount <= 0: raise ValueError("amount must be positive") if amount > balance: raise ValueError("insufficient balance") return balance - amount try: new_bal = withdraw(5000, 8000) except ValueError as e: print("Transaction failed:", e)
Transaction failed: insufficient balance

3.7.2 Re-raising the current exception

Sometimes a function wants to log the error but still let the caller know something went wrong. Use a bare raise inside except to re-throw the same exception.

try: x = int(input()) except ValueError: print("Invalid input — passing error upwards.") raise # re-raises the ValueError so the caller can handle it

3.7.3 Choosing the right exception class

SituationUse
Value has the right type but a wrong valueValueError
Wrong type was passedTypeError
Key missing from a dictionaryKeyError
Index out of rangeIndexError
Operation not supported in this stateRuntimeError

3.8 Nested try Blocks

A try can contain another try. Useful when the inner operation has its own specific failure that you want to handle before falling back to the outer handler.

try: f = open("data.txt") try: n = int(f.readline()) print("First number:", n) except ValueError: print("The first line was not a number.") finally: f.close() except FileNotFoundError: print("File not found.")

3.9 CBSE-style Worked Programs

3.9.1 Safe division

def safe_div(a, b): try: return a / b except ZeroDivisionError: return "Error: divide-by-zero" print(safe_div(10, 2)) # 5.0 print(safe_div(10, 0)) # Error: divide-by-zero

3.9.2 Retry until the user enters a valid number

while True: try: age = int(input("Your age: ")) break # success — leave the loop except ValueError: print("Enter digits only — try again.") print("Hello! You are", age)

3.9.3 Handle a missing dictionary key

prices = {"pen": 10, "book": 150, "bag": 600} item = input("Item: ") try: print(item, "costs ₹", prices[item]) except KeyError: print("Sorry — we do not stock", item)

3.9.4 Opening a file safely

try: f = open("notes.txt", "r") except FileNotFoundError: print("Creating the file for the first time.") f = open("notes.txt", "w") else: print(f.read()) finally: f.close()

3.9.5 Validating a mark between 0 and 100 using raise

def validate_marks(m): if not (0 <= m <= 100): raise ValueError(f"marks must be between 0 and 100 (got {m})") return m try: validate_marks(105) except ValueError as e: print("Invalid:", e)
Invalid: marks must be between 0 and 100 (got 105)

3.9.6 Summation with per-entry error reporting

def sum_strings(items): total = 0 for i, s in enumerate(items, start=1): try: total += int(s) except ValueError: print(f" (ignored item #{i}: '{s}' is not a number)") return total print("Sum =", sum_strings(["10", "20", "abc", "40", "xyz"]))
(ignored item #3: 'abc' is not a number) (ignored item #5: 'xyz' is not a number) Sum = 70

3.9.7 Calculator with menu

def calc(): try: a = float(input("a: ")) b = float(input("b: ")) op = input("op (+ - * /): ").strip() if op == "+": r = a + b elif op == "-": r = a - b elif op == "*": r = a * b elif op == "/": r = a / b else: raise ValueError("Unknown operator") print("Result =", r) except ValueError as e: print("Input error:", e) except ZeroDivisionError: print("Error: dividing by zero is not allowed.") finally: print("— end of calculation —") calc()

3.10 Common Mistakes to Avoid

#MistakeFix
1Using a bare except: that silently swallows every errorCatch the specific exception — or at least except Exception as e and print e
2Putting “success” code inside try so wrong errors get blamedPut only the risky line in try; put success code in else
3Forgetting to close a file when an exception happensClose it in finally, or use with open(…) as f:
4Raising a plain Exception when a more specific class fitsUse ValueError, TypeError, KeyError, etc.
5Using try/except to hide genuine bugs in your codeExceptions are for external failures (bad input, missing file), not for logic errors
6Handling the wrong exception type, so the real one still crashesRead the traceback — the last line names the exact exception to catch

Quick-revision summary

  • An exception is a run-time error. Syntax errors cannot be handled — you must fix the code first.
  • try wraps the risky code; except catches one (or more) exception types and responds.
  • except (A, B): catches either exception; except E as e: captures the exception object for its message.
  • else runs only when the try succeeds (no exception).
  • finally always runs — ideal for clean-up (closing files, disconnecting).
  • raise ExceptionType("msg") throws an exception on purpose; a bare raise re-throws the current exception.
  • Prefer specific exception classes; avoid bare except:.
  • Use try/except for external failures; do not use it to hide bugs in your own logic.
🧠Practice Quiz — test yourself on this chapter