Excellent.
DAY 22 is about error handling done right — not just catching errors, but understanding how exceptions work internally, their cost, and how to design clean failure paths.
Most production Python bugs are exception-design bugs, not syntax bugs.
🧠 DAY 22 — Exceptions Internals
(Hierarchy, Cost Model & Pythonic Error Handling)
🔑 CORE IDEA OF DAY 22
Exceptions are a control-flow mechanism with runtime cost.
Use them to represent exceptional states, not normal logic.
1️⃣ What an Exception REALLY Is
An exception is:
- An object
- Derived from
BaseException - Created, raised, propagated, and optionally handled
try:
x = 1 / 0
except ZeroDivisionError as e:
print(type(e))
✔ ZeroDivisionError is an object with:
- Type
- Message
- Traceback
2️⃣ Exception Hierarchy (CRITICAL)




Top-level:
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── ArithmeticError
│ └── ZeroDivisionError
├── ValueError
├── TypeError
├── KeyError
└── ...
Golden rule:
Catch
Exception, notBaseException
Catching BaseException hides:
- Ctrl+C
- System exits
- Generator shutdown
3️⃣ Raising Exceptions (Explicit Control)
raise ValueError("invalid input")
Or re-raise:
try:
risky()
except ValueError:
raise
This preserves the original traceback.
4️⃣ How Exceptions Propagate (Stack Unwinding)
When an exception occurs:
- Current frame stops
- Stack unwinds frame by frame
- Python looks for a matching
except - If none found → program crashes
This is why tracebacks show call stacks.
5️⃣ try / except / else / finally (FULL MODEL)
try:
x = int("10")
except ValueError:
print("bad input")
else:
print("success")
finally:
print("cleanup")
Rules:
except→ only on exceptionelse→ only if no exceptionfinally→ always
🧠 Use else to avoid catching errors unintentionally.
6️⃣ Exception Objects Carry Tracebacks
import traceback
try:
1 / 0
except Exception as e:
traceback.print_exc()
Tracebacks are:
- Linked to frames
- Useful for debugging
- Expensive to create
7️⃣ Why Exceptions Are SLOW (Important for Design)
Raising an exception:
- Allocates exception object
- Captures traceback
- Unwinds stack
Compared to:
if x == 0:
...
👉 Exceptions are orders of magnitude slower than conditionals
Rule:
Don’t use exceptions for normal control flow.
8️⃣ EAFP vs LBYL (Python Philosophy)
LBYL — Look Before You Leap
if key in d:
value = d[key]
EAFP — Easier to Ask Forgiveness
try:
value = d[key]
except KeyError:
...
Python often prefers EAFP, because:
- Cleaner code
- Avoids race conditions
- Reads naturally
But:
- Use EAFP where failure is rare
- Use LBYL in hot loops
9️⃣ Writing Custom Exceptions (BEST PRACTICE)
class ConfigError(Exception):
pass
Why subclass Exception?
- Integrates with ecosystem
- Can be selectively caught
- Semantic clarity
Avoid:
class MyError(BaseException): # ❌
pass
🔟 finally vs Context Managers
Bad:
f = open("file")
try:
data = f.read()
finally:
f.close()
Better:
with open("file") as f:
data = f.read()
Context managers:
- Cleaner
- Safer
- Exception-aware by design
11️⃣ Exception Chaining (Advanced, Interview Gold)
try:
int("x")
except ValueError as e:
raise RuntimeError("conversion failed") from e
Traceback shows:
The above exception was the direct cause of...
This preserves root cause.
12️⃣ Silent Exception Anti-Pattern 🚨
try:
do_something()
except Exception:
pass
This:
- Hides bugs
- Breaks debugging
- Fails silently
Always:
- Log
- Re-raise
- Or handle explicitly
🔥 INTERVIEW TRAPS (DAY 22)
Q1
Why shouldn’t we catch BaseException?
✔ Swallows KeyboardInterrupt
✔ Prevents graceful exit
Q2
Which is faster?
if x in d:
or
try: d[x]
✔ Depends on failure frequency
✔ if faster when misses common
Q3
Why context managers are preferred over try/finally?
✔ Less error-prone
✔ Cleaner semantics
✔ Automatic cleanup
🧠 DAY 22 MENTAL CHECKLIST
When handling errors:
- Is this exceptional or normal?
- Should I use EAFP or LBYL?
- Am I catching too broadly?
- Is cleanup guaranteed?
- Is error information preserved?
📝 DAY 22 ASSIGNMENT (MANDATORY)
1️⃣ Predict output (NO RUNNING):
try:
raise ValueError("x")
except Exception:
print("A")
finally:
print("B")
2️⃣ Explain clearly:
- Why exceptions are slow
- Difference between
exceptandelse
3️⃣ Design question:
How would you design error handling for a data pipeline step that can fail due to bad input, network issues, or system shutdown?
(Hint: custom exceptions + chaining)
🔜 DAY 23 PREVIEW
DAY 23 — Iterators & Generators (Lazy Evaluation & State Machines)
You’ll learn:
- Iterator protocol deeply
- How generators pause/resume execution
- Memory benefits
- Why generators power Python’s scalability
When ready, say 👉 “START DAY 23”