Exception Handling
# Exception Handling
Welcome to Chapter 17! Errors happen in every program. Exception handling lets you deal with errors gracefully instead of crashing.
---
1. Learning Objectives
- Understand exceptions vs syntax errors.
- Use try, except, else, and finally blocks.
- Raise custom exceptions.
- Create custom exception classes.
- Apply debugging best practices.
---
2. Types of Errors
```python id="py17_ex1" # SyntaxError — caught before execution # print("Hello" ← Missing closing parenthesis
# Runtime exceptions — caught during execution # print(10 / 0) → ZeroDivisionError # int("abc") → ValueError # print(undefined) → NameError # [1,2,3][10] → IndexError # {"a": 1}["b"] → KeyError # open("nope.txt") → FileNotFoundError
python id="py17_ex2" # Basic exception handling try: num = int(input("Enter a number: ")) result = 100 / num print(f"Result: {result}") except ZeroDivisionError: print("❌ Cannot divide by zero!") except ValueError: print("❌ Invalid number!") except Exception as e: print(f"❌ Unexpected error: {e}")
python id="py17_ex3" try: file = open("data.txt", "r") content = file.read() except FileNotFoundError: print("❌ File not found!") else: # Runs ONLY if no exception occurred print(f"✅ File read: {len(content)} characters") finally: # ALWAYS runs (cleanup code) print("🔧 Cleanup complete")
Exception Flow: try → [Error?] → Yes → except → finally → No → else → finally
python id="py17ex4" def setage(age): if age < 0: raise ValueError("Age cannot be negative!") if age > 150: raise ValueError("Age seems unrealistic!") return age
try: set_age(-5) except ValueError as e: print(f"Error: {e}")
python id="py17ex5" class InsufficientFundsError(Exception): def init(self, balance, amount): self.balance = balance self.amount = amount super().init(f"Cannot withdraw ${amount}. Balance: ${balance}")
class BankAccount: def init_(self, balance): self.balance = balance def withdraw(self, amount): if amount > self.balance: raise InsufficientFundsError(self.balance, amount) self.balance -= amount return self.balance
account = BankAccount(100) try: account.withdraw(150) except InsufficientFundsError as e: print(f"❌ {e}")
python id="py17ex6" def getint(prompt, minval=None, maxval=None): while True: try: value = int(input(prompt)) if minval is not None and value < minval: print(f" Must be >= {minval}") continue if maxval is not None and value > maxval: print(f" Must be <= {maxval}") continue return value except ValueError: print(" ❌ Please enter a valid number!")
age = getint("Enter age (1-120): ", 1, 120)
print(f"Age: {age}")
``
---
9. MCQs with Answers
Q1: finally block runs:
A) Only on error B) Only on success C) Always D) Never
Answer: C
Q2: else in try block runs when:
A) Error occurs B) No error occurs C) Always D) After finally
Answer: B
Q3: raise does:
A) Catches error B) Throws an exception C) Ignores error D) Logs error
Answer: B
Q4: except Exception as e — e is:
A) Error code B) Error message object C) Error line number D) Error file
Answer: B
Q5: Custom exceptions should inherit from: A) object B) Exception C) Error D) BaseException Answer: B
Q6: try without except:
A) Works fine B) SyntaxError C) RuntimeError D) Warning
Answer: B — Need at least except or finally.
Q7: Bare except: catches:
A) Nothing B) All exceptions C) Only ValueError D) Only RuntimeError
Answer: B — But it's bad practice.
Q8: Best practice for catching exceptions: A) Catch all B) Catch specific types C) Never catch D) Use if-else Answer: B
Q9: assert x > 0 raises:
A) ValueError B) AssertionError C) TypeError D) RuntimeError
Answer: B
Q10: LBYL vs EAFP? A) Same thing B) LBYL checks before, EAFP uses try/except C) Both outdated D) EAFP checks before Answer: B — Python prefers EAFP (Easier to Ask Forgiveness than Permission).
---
10. Interview Questions
- 1. try vs if for error handling? Python prefers EAFP (try/except) over LBYL (if checks). try/except is more Pythonic.
- 2. When to use custom exceptions? For domain-specific errors that need special handling (e.g., InsufficientFundsError).
- 3. Difference between Exception and BaseException? BaseException is the root; Exception is for catchable errors. SystemExit and KeyboardInterrupt inherit from BaseException.
- 4. What is exception chaining? raise NewError() from originalerror` — preserves the original exception context.
- 5. Can finally modify return values? Yes, a return in finally overrides the try block's return.
---
11. Summary
- try/except catches and handles exceptions gracefully.
- else runs when no exception occurs; finally always runs.
- raise throws exceptions; create custom exceptions by inheriting from Exception.
- Catch specific exceptions, not bare except.
- Python prefers EAFP (try/except) over LBYL (if checks).
---
12. Next Chapter Recommendation
In Chapter 18: Object-Oriented Programming (OOP), you'll learn classes, objects, constructors, and build a bank account system! 🚀