FROM FIRST PRINCIPLES: When Python sees a raise, it walks up the exception hierarchy looking for a matching except clause.
Step-by-step:
Exception raised: KeyError('missing_key')
Python checks: Is there an except KeyError? ✓ Match!
If not found, check parent: Is there an except LookupError? ✓ Match!
If not found, check grandparent: Is there an except Exception? ✓ Match!
Continue until BaseException or no handler found (crash)
WHY this ordering matters:
# ❌ WRONG - Dead code below!try: data[key]except Exception as e: # Catches EVERYTHING first print("General error")except KeyError as e: # NEVER REACHED - KeyError is a child of Exception print("Key missing")
WHY? Python checks handlers top to bottom. KeyError IS-A Exception, so the first handler always wins.
# ✅ CORRECT - Specific to generaltry: data[key]except KeyError as e: # Checked first - catches KeyError print(f"Missing key: {e}")except LookupError as e: # Catches IndexError (sibling of KeyError) print(f"Lookup failed: {e}")except Exception as e: # Catches everything else print(f"Unexpected: {e}")
Recall Feynman Explanation (Explain to a 12-year-old)
Imagine your teacher asks you to organize all animals. You might say:
LivingThings (top of tree)
Animals
Mammals
Dogs, Cats, Whales
Birds
Parrots, Eagles
Python does the same with errors! Instead of "Animals," we have "Exceptions." Instead of "Mammals," we have "ArithmeticError" (math problems) or "LookupError" (can't find something).
When you write except Mammals, you catch all dogs and cats automatically. When you write except Dogs, you ONLY catch dogs.
The rule: If you want to catch a dog, you can say "catch dogs" OR "catch mammals" OR "catch animals"—they all work because dogs belong to all three families. But if you only care about dogs, be specific! Say "catch dogs" so you don't accidentally catch cats.
In Python: except KeyError (specific) vs except LookupError (catches KeyError + IndexError) vs except Exception (catches almost everything).
2.1.04-Inheritance — Exception hierarchy uses class inheritance (IS-A relationships)
3.2.05-Logging — Log exceptions with proper specificity (don't swallow with bare except)
#flashcards/coding
What is the root of Python's exception hierarchy?
BaseException (parent of SystemExit, KeyboardInterrupt, and Exception)
Why should you use except Exception instead of except BaseException for normal error handling?
BaseException catches SystemExit and KeyboardInterrupt, which would prevent program termination and Ctrl+C from working. Exception catches only normal errors.
What is the parent exception of both KeyError and IndexError?
LookupError (both are children of LookupError)
Why must specific exception handlers come before general ones?
Python checks handlers sequentially top-to-bottom. If a general handler (like except Exception) comes first, it catches child exceptions before specific handlers can run, making them unreachable dead code.
What happens if you raise KeyError and only have except LookupError in your handler?
The LookupError handler catches it, because KeyError IS-A LookupError (inheritance)
When would you use except OSError instead of specific handlers?
As a safety net after specific handlers (FileNotFoundError, PermissionError) to catch unexpected OS-level errors like disk full or network failures
What's the danger of except Exception: pass in production code?
It silently swallows all errors including bugs, making debugging impossible. You don't know when things fail.
Does 10**1000 / 10**999 raise OverflowError?
No—it equals 10.0. Integer division promotes correctly. OverflowError only occurs with FLOAT operands whose result exceeds the max float (~1.8e308), e.g. 1e308 / 1e-10.
Dekho yaar, Python ne saare exceptions ko ek family tree ki tarah organize kiya hai, jaise ek khandaan hota hai jahan sabka ek common daada hota hai. Yahan sabse upar BaseException baitha hai, uske neeche Exception aata hai, aur uske neeche chote-chote specific errors jaise KeyError, IndexError, ZeroDivisionError waghera. Core intuition ye hai ki jab tum kisi parent exception ko catch karte ho, toh uske saare children automatically catch ho jaate hain. Jaise agar tum "mammals" pakadne jaao, toh dogs bhi aa jaayenge kyunki dog ek mammal hai. Isi tarah except LookupError likhne se KeyError aur IndexError dono pakde jaate hain, kyunki ye dono LookupError ke bacche hain.
Ab ye baat kyun important hai? Kyunki Python except clauses ko top se bottom check karta hai, aur jo pehla match ho jaaye wahi jeet jaata hai. Isliye tumhe hamesha specific error pehle aur general error baad mein likhna hota hai. Agar tumne galti se except Exception sabse upar likh diya, toh neeche ka except KeyError kabhi chalega hi nahi—wo dead code ban jaayega, kyunki KeyError bhi toh ek Exception hi hai, aur pehla handler use pehle hi pakad lega. Ye ek bahut common mistake hai jo beginners karte hain.
Toh practical baat ye hai ki jab bhi error handle karo, sabse specific ancestor use karo jo tumhare kaam ke exceptions cover karta ho—na zyada broad, na zyada narrow. except BaseException toh bilkul avoid karo kyunki wo Ctrl+C (KeyboardInterrupt) aur system-exit tak pakad leta hai, jo tumhare program ko kabhi band hi nahi hone dega—bahut dangerous hai. Is hierarchy ko samajhne se tum "surgical precision" ke saath errors handle kar paoge, matlab exactly wahi pakadoge jo tumhe chahiye, aur baaki errors ko naturally aage jaane doge. Ye skill real projects mein bahut kaam aati hai jab tumhe clean aur robust code likhna ho.