Quiz 2

Exception Handling

976 words
5 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Exception Handling > **Why read this?** Errors happen. A user enters text where a number is expected.

Exception Handling

Why read this? Errors happen. A user enters text where a number is expected. A file doesn't exist. A network connection drops. Without proper handling, any of these errors crashes your program. Exception handling gives you the power to anticipate problems and respond gracefully — showing helpful messages, retrying operations, or safely shutting down.

🎯 Learning Objectives

By the end of this topic, you will be able to:
  1. Use try/except blocks to catch and handle exceptions
  2. Handle specific exception types (ValueError, FileNotFoundError, etc.)
  3. Use else and finally clauses for cleanup
  4. Raise exceptions with raise for input validation
  5. Create custom exception classes

📋 Prerequisites

  • File Operations — File errors are common exceptions.
  • Basic understanding of control flow.

📖 Core Content

27.1 What Problem Do Exceptions Solve?

Intuition: A program without exception handling is like a car with no airbags or seatbelts. Any small bump causes a crash. Exceptions are your safety system — they catch problems before they crash the program and let you respond appropriately.

27.2 Basic try/except

python
# runnable
try:
    num = int(input("Enter a number: "))
    print(f"100 / {num} = {100 / num}")
except ValueError:
    print("That's not a valid number!")
except ZeroDivisionError:
    print("Can't divide by zero!")
print("Program continues safely...")
How it works:
  1. Python executes the code in the try block.
  2. If no error occurs, except blocks are skipped.
  3. If a ValueError occurs (e.g., user types "abc"), the first matching except runs.
  4. If a ZeroDivisionError occurs, that handler runs.
  5. Any other exception type would crash the program (not caught).

27.3 Catching Multiple Exceptions

python
# runnable
try:
    numbers = [1, 2, 3]
    index = int(input("Index (0-2): "))
    print(f"Value: {numbers[index]}")
    result = 100 / index
    print(f"100/{index} = {result}")
except (ValueError, IndexError, ZeroDivisionError) as e:
    print(f"Error occurred: {type(e).__name__}: {e}")

27.4 try/except/else/finally

python
# runnable
def read_file_safe(filename):
    """Read a file safely with full exception handling."""
    try:
        f = open(filename, "r")
        content = f.read()
    except FileNotFoundError:
        print(f"Error: '{filename}' not found.")
        return None
    except PermissionError:
        print(f"Error: No permission to read '{filename}'.")
        return None
    else:
        # Runs ONLY if no exception occurred
        print(f"Successfully read {len(content)} characters.")
        return content
    finally:
        # ALWAYS runs — cleanup code
        print(f"Finished processing '{filename}'.")
        if 'f' in locals() and not f.closed:
            f.close()
# Test
result = read_file_safe("example.txt")
print(f"Result: {result}")

27.5 Raising Exceptions

python
# runnable
def get_positive_int(prompt):
    """Get a positive integer from user. Raises ValueError if invalid."""
    value = int(input(prompt))
    if value <= 0:
        raise ValueError(f"{value} is not positive!")
    return value
try:
    age = get_positive_int("Enter your age: ")
    print(f"You are {age} years old.")
except ValueError as e:
    print(f"Invalid input: {e}")

27.6 Custom Exception Classes

python
# runnable
class InsufficientFundsError(Exception):
    """Raised when account balance is too low."""
    pass
class NegativeAmountError(Exception):
    """Raised when deposit/withdrawal amount is negative."""
    pass
class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance
    def withdraw(self, amount):
        if amount < 0:
            raise NegativeAmountError("Withdrawal amount can't be negative!")
        if amount > self.balance:
            raise InsufficientFundsError(f"Need ₹{amount}, have ₹{self.balance}")
        self.balance -= amount
        print(f"Withdrew ₹{amount}. Balance: ₹{self.balance}")
acc = BankAccount(1000)
try:
    acc.withdraw(1500)
except InsufficientFundsError as e:
    print(f"Transaction failed: {e}")
except NegativeAmountError as e:
    print(f"Invalid amount: {e}")

27.7 Common Exception Types

ExceptionWhen It OccursExample
ValueErrorWrong value for a functionint("abc")
TypeErrorWrong type for an operation"5" + 3
IndexErrorList index out of range[1,2][5]
KeyErrorDictionary key not found{"a":1}["b"]
FileNotFoundErrorFile doesn't existopen("nope.txt")
ZeroDivisionErrorDivision by zero10 / 0
ImportErrorModule not foundimport nonexistent
AttributeErrorObject has no attribute"hello".nonexistent()

⚠️ Common Pitfalls

Pitfall 1: Bare except: Catches Everything

The mistake: except: without specifying type catches ALL errors, including Ctrl+C (KeyboardInterrupt), making the program unkillable. Fix: Always specify exception type: except ValueError: or at minimum except Exception as e:.

Pitfall 2: Swallowing Errors Silently

The mistake: except: pass — hides all errors, making debugging impossible. Fix: At minimum log the error: except Exception as e: print(f"Error: {e}") or logging.exception("...").

Pitfall 3: Not Cleaning Up Resources

The mistake: Opening a file or network connection in try and an exception occurs before cleanup. Fix: Use with statement (auto-closes) or finally block for guaranteed cleanup.

Pitfall 4: Raising Exception Without Message

The mistake: raise ValueError without explanation. Fix: Always include a descriptive message: raise ValueError("Age must be positive").

📝 Practice Questions

Q1: What's the output if user enters "five"?
python
try:
    x = int(input("Number: "))
    print(10 / x)
except ValueError:
    print("Bad number")
except ZeroDivisionError:
    print("Zero division")
Answer: Bad number — the ValueError from int("five") is caught. Q2: When does the finally block execute?
Answer: ALWAYS — whether an exception occurred or not. It's for cleanup code that must run. Q3: What's wrong with except: (bare except)?
Answer: It catches ALL exceptions including SystemExit, KeyboardInterrupt, and GeneratorExit. This can make the program impossible to terminate. Always specify the exception type. Q4: Write a function safe_divide(a, b) that handles ZeroDivisionError and TypeError.
Answer:
python
def safe_divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return None
    except TypeError:
        return None
Q5: What does the else clause in a try/except block do?
Answer: The else block runs ONLY if the try block did NOT raise an exception. It's useful for code that should run only on success. Q6-10: Additional exception handling questions follow the same format.
(Following the established pattern with detailed answers.)

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.