Session 12 of the Python Fundamentals series, covered in depth. Its aim is to stop you fearing the red text. It shows how to read a traceback from the bottom up and how to recognize the common errors - NameError, TypeError, ValueError, IndexError, KeyError, ZeroDivisionError, SyntaxError, and IndentationError - along with their exact messages. It then guards risky code with try and except, catches specific error types, captures the message with "as e", and validates input in a loop, before covering how to debug by printing values, reproducing the problem, and narrowing it down. The traps are a bare except that hides bugs, and catching the wrong error type. Every snippet, message, and traceback was copied verbatim from CPython 3.12.
Subject: Python Fundamentals · 95 slides · code lesson
Open the interactive version of this deck · Homework for this lesson
Title
Python Fundamentals - Session 12
Read the message, fix the bug - and stop fearing the red text
Objectives
Everyone's code breaks. The error message tells you where and why. By the end you can:
try / except.Warm-up
Discussion prompt
Before we open Session 12 - Errors & Debugging: without looking back, what was the main idea of Session 11 - Strings Toolkit, and what could you do by the end of it that you could not do before?
Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.
Answer:
That session covers .lower(), .upper(), and .strip(), the in operator with .startswith() and .endswith(), length, indexing, and slicing, .split() and .replace(), f-strings, and the immutability trap.
Section
Part 1
Concept
Errors are not a sign you are bad at this - they are a normal, constant part of programming for everyone.
The skill is not avoiding errors; it is reading them and fixing them quickly.
Counterexample
Discussion prompt
Errors are not a sign you are bad at this - they are a normal, constant part of programming for everyone.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Answer:
The skill is not avoiding errors; it is reading them and fixing them quickly.
Concept
When Python hits something it cannot do, it stops and prints a traceback - a report of what went wrong and where.
traceback — The error report Python prints when it stops. It shows the chain of calls that led to the error, ending with the error type and message.
Analogy
Discussion prompt
Explain An error stops and explains by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
When Python hits something it cannot do, it stops and prints a traceback - a report of what went wrong and where.
Intuition
Treat the red text as a helpful note, not a scolding. It literally tells you the file, the line, and the reason.
Most beginners' real problem is not the bug - it is not reading the message. Slow down and read it.
Explain it
Discussion prompt
Explain The error is trying to help to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Treat the red text as a helpful note, not a scolding. It literally tells you the file, the line, and the reason.
Section
Part 2
Concept
The last line is the most important: it names the error type and the message. Start there.
The lines above trace how Python got there - the most recent call is at the bottom.
Pattern
Predict first
The table runs: File ... line 4, in <module> | where it started: the call · File ... line 2, in greet | where it actually failed · return "Hi " + naem | the exact line
In Anatomy of a traceback, given the rows so far: what is the next one — the row where traceback part is NameError: name 'naem' is not defined?
Correct: NameError: name 'naem' is not defined | the type and reason
| traceback part | tells you |
|---|---|
| File ... line 4, in <module> | where it started: the call |
| File ... line 2, in greet | where it actually failed |
| return "Hi " + naem | the exact line |
| NameError: name 'naem' is not defined | the type and reason |
Why: The relationship between the columns, not the individual numbers, is what generates the next row. It says NameError: name 'naem' is not defined - a typo'd variable.
Worked example
A misspelled naem inside a function:
def greet(name):
return "Hi " + naem
print(greet("Sam"))Read the bottom line first
Why: It says NameError: name 'naem' is not defined - a typo'd variable.
| traceback part | tells you |
|---|---|
| File ... line 4, in <module> | where it started: the call |
| File ... line 2, in greet | where it actually failed |
| return "Hi " + naem | the exact line |
| NameError: name 'naem' is not defined | the type and reason |
The fix follows from the message
Why: Verified by execution: this is the real traceback. naem should be name; correcting the spelling fixes it.
Comparison
Comparison matrix
From Anatomy of a traceback: refill the tells you column from what you know. The rest of the table is as it appeared.
| traceback part | tells you |
|---|---|
| File ... line 4, in <module> | where it started: the call |
| File ... line 2, in greet | where it actually failed |
| return "Hi " + naem | the exact line |
| NameError: name 'naem' is not defined | the type and reason |
Concept
Each frame gives a file and line number, and shows the offending line with a caret ^ under the problem.
Jump to that line first - the bug is there or very close to it.
Section
Part 3
Concept
NameError: name 'x' is not defined - you used a name Python does not know: a typo, forgotten quotes, or a variable used before it was created.
Worked example
print(x)x was never assigned
Why: No variable x exists, so Python cannot look it up.
| code | error |
|---|---|
| print(x) | NameError: name 'x' is not defined |
Fix
Why: Define x first (x = 5), add quotes if you meant text, or fix the spelling.
Blank canvas
Draw it
Draw what NameError in action just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.
Concept
TypeError - an operation got the wrong type, like adding a string and a number.
Sorting
Sort into buckets
These are the pieces of Session 12 - Errors & Debugging, out of order. Put each one back under the part of the lesson it belongs to.
Worked example
print("a" + 5)str + int is not allowed
Why: One side is text, the other a number.
| code | error |
|---|---|
| "a" + 5 | TypeError: can only concatenate str (not "int") to str |
Fix
Why: Convert one side: "a" + str(5), or use a comma / f-string.
Concept
ValueError - the type was right but the value was not usable, like converting non-numeric text with int().
Worked example
print(int("abc"))"abc" is not a number
Why: int() got a string (right type) but no digits to read (wrong value).
| code | error |
|---|---|
| int("abc") | ValueError: invalid literal for int() with base 10: 'abc' |
Fix
Why: Only convert text that is actually numeric - or guard it with try/except (coming up).
Explain it to yourself
Discussion prompt
In IndexError and KeyError this move is made:
IndexError: past the end of a list
Why is that legal? Name the rule or definition it rests on before you read on.
Hint: If you can only say "because that is what you do", the rule is the thing to go and find.
Answer:
The list has indexes 0 and 1; 5 is out of range.
Worked example
print([1, 2][5])
print({"a": 1}["b"])IndexError: past the end of a list
Why: The list has indexes 0 and 1; 5 is out of range.
KeyError: a missing dict key
Why: Verified by execution: the dict has no key "b".
| code | error |
|---|---|
| [1, 2][5] | IndexError: list index out of range |
| {"a": 1}["b"] | KeyError: 'b' |
Trade off
Comparison matrix
From IndexError and KeyError: every row here is a choice with a cost. Fill the error column, then say which row you would actually pick and what you give up for it.
| code | error |
|---|---|
| [1, 2][5] | IndexError: list index out of range |
| {"a": 1}["b"] | KeyError: 'b' |
Worked example
print(10 / 0)Dividing by zero is undefined
Why: Python refuses and reports the reason.
| code | error |
|---|---|
| 10 / 0 | ZeroDivisionError: division by zero |
Fix
Why: Check the divisor first: if divisor != 0, or guard with try/except.
Concept
SyntaxError and IndentationError happen before the program runs - the code is not valid Python, so nothing executes.
The others above happen while running. A syntax error means 'I cannot even read this line'; a runtime error means 'I ran, then hit a problem'.
Section
Part 4
Concept
Put risky code in a try: block. If it raises an error, Python jumps to the except: block instead of crashing.
This lets a bad input recover gracefully rather than stopping the whole program.
Fill the middle
Fill in the blanks
From Guarding a conversion — one line has had its right-hand side removed. Put it back.
try:
age = int(input("Age? "))
print("Next year:", age + 1)
except ValueError:
print("Please type a whole number.")
Why: age is what everything below it consumes, so the wrong expression here fails later and somewhere else. "abc" cannot convert, so a ValueError is raised.
Worked example
The user types abc:
try:
age = int(input("Age? "))
print("Next year:", age + 1)
except ValueError:
print("Please type a whole number.")The int() fails inside try
Why: "abc" cannot convert, so a ValueError is raised.
except handles it instead of crashing
Why: Verified by execution: prints Please type a whole number. A valid number would run the try block normally.
| user types | path | prints |
|---|---|---|
| abc | except | Please type a whole number. |
| 20 | try | Next year: 21 |
Error analysis
Annotate
Walk the callouts on Guarding a conversion. Each one is a place this is easy to get subtly wrong.
Concept
Name the error after except: except ValueError:. This catches only that kind, and lets unrelated bugs still surface.
Catch the specific error you expect, not everything - that way real, unexpected bugs are not hidden.
Explain it to yourself
Discussion prompt
In Only the error you expect this move is made:
Read the output
Why is that legal? Name the rule or definition it rests on before you read on.
Hint: If you can only say "because that is what you do", the rule is the thing to go and find.
Answer:
Verified by execution: prints cannot divide by zero. A different error would not be caught here.
Worked example
try:
print(10 / 0)
except ZeroDivisionError:
print("cannot divide by zero")except ZeroDivisionError matches
Why: The division raises exactly that error, so this block runs.
Read the output
Why: Verified by execution: prints cannot divide by zero. A different error would not be caught here.
| error raised | caught? |
|---|---|
| ZeroDivisionError | yes |
| (a different error) | no - surfaces normally |
Intuition
Picture a tightrope walker with a net. The try is the walk; the except is the net that catches a specific fall.
Use it where a fall is expected and recoverable - like user input - not to paper over bugs you have not understood.
Concept
except ValueError as e: gives you the error object e, whose text you can print or log for more detail.
Socratic
Discussion prompt
except ValueError as e: gives you the error object e, whose text you can print or log for more detail.
Suppose that were not true. What is the first thing in Session 12 - Errors & Debugging that would stop working?
Hint: Follow it one step downstream. The answer is whatever was quietly relying on it.
Explain it to yourself
Discussion prompt
In Reading the message this move is made:
Read the output
Why is that legal? Name the rule or definition it rests on before you read on.
Hint: If you can only say "because that is what you do", the rule is the thing to go and find.
Answer:
Verified by execution: caught: invalid literal for int() with base 10: 'abc'.
Worked example
try:
int("abc")
except ValueError as e:
print("caught:", e)e holds the error's message
Why: You can show it to help the user or yourself.
Read the output
Why: Verified by execution: caught: invalid literal for int() with base 10: 'abc'.
| expression | prints |
|---|---|
| print("caught:", e) | caught: invalid literal ... 'abc' |
Section
Part 5
Concept
Combine try/except with a loop: keep asking until the input converts cleanly, then break out.
This is the robust way to demand a number without crashing on a typo.
Explain it to yourself
Discussion prompt
In Keep asking until valid this move is made:
A good value breaks out
Why is that legal? Name the rule or definition it rests on before you read on.
Hint: If you can only say "because that is what you do", the rule is the thing to go and find.
Answer:
Verified by execution: prints not a number, try again, then got 12.
Worked example
The user types abc, then 12:
while True:
try:
n = int(input("A number: "))
break
except ValueError:
print("not a number, try again")
print("got", n)A bad value is caught and the loop repeats
Why: abc raises ValueError, so except runs and the loop asks again.
A good value breaks out
Why: Verified by execution: prints not a number, try again, then got 12.
| user types | result |
|---|---|
| abc | not a number, try again |
| 12 | got 12 |
Concept
You can check first (if b != 0:) or catch the error (except ZeroDivisionError). Either prevents a crash.
Explain it to yourself
Discussion prompt
In A safe divide this move is made:
Check the divisor before dividing
Why is that legal? Name the rule or definition it rests on before you read on.
Hint: If you can only say "because that is what you do", the rule is the thing to go and find.
Answer:
If b is 0, return a message instead of dividing.
Worked example
def safe_divide(a, b):
if b == 0:
return "undefined"
return a / b
print(safe_divide(10, 2))
print(safe_divide(10, 0))Check the divisor before dividing
Why: If b is 0, return a message instead of dividing.
Read the output
Why: Verified by execution: 5.0, then undefined.
| call | returns |
|---|---|
| safe_divide(10, 2) | 5.0 |
| safe_divide(10, 0) | undefined |
Section
Part 6
Anomaly
Predict first
A student writes this, and it looks reasonable:
Catching everything with a bare except.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: inpt is a typo for input - a NameError.
Catch only the error you expect.
Why: inpt is a typo for input - a NameError. But the bare except catches it too and blames 'bad input', hiding the actual mistake.
Trap
Catching everything with a bare except.
try:
n = int(inpt("Age? "))
except:
print("bad input")It swallows the real bug
Why: inpt is a typo for input - a NameError. But the bare except catches it too and blames 'bad input', hiding the actual mistake.
| real problem | what you see |
|---|---|
| NameError (typo inpt) | bad input |
Catch only the error you expect.
try:
n = int(input("Age? "))
except ValueError:
print("please type a number")A ValueError is handled; other bugs surface
Why: Now a typo like inpt would raise a NameError you can see and fix, instead of being masked. Catch narrowly.
| error | behavior |
|---|---|
| ValueError | handled kindly |
| NameError (a real bug) | surfaces so you fix it |
Comparison
Comparison matrix
From Trap: a bare except hides bugs: refill the behavior column from what you know. The rest of the table is as it appeared.
| error | behavior |
|---|---|
| ValueError | handled kindly |
| NameError (a real bug) | surfaces so you fix it |
Concept
Only wrap code in try/except when you have a sensible recovery. If you cannot recover, let it crash - the traceback is more useful than a swallowed error.
Anomaly
Predict first
A student writes this, and it looks reasonable:
Expecting except TypeError to catch a bad conversion.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: The except only catches TypeError, so the ValueError slips past and the program still crashes.
Match the except to the error actually raised.
Why: The except only catches TypeError, so the ValueError slips past and the program still crashes.
Trap
Expecting except TypeError to catch a bad conversion.
try:
n = int("abc")
except TypeError:
print("handled")int("abc") raises ValueError, not TypeError
Why: The except only catches TypeError, so the ValueError slips past and the program still crashes.
| raised | except catches | result |
|---|---|---|
| ValueError | TypeError | still crashes |
Match the except to the error actually raised.
try:
n = int("abc")
except ValueError:
print("handled")except ValueError matches
Why: Now the right error is caught. Real output: handled. Read the traceback to learn which type to catch.
| raised | except catches | result |
|---|---|---|
| ValueError | ValueError | handled |
Two truths and a lie
Sort into buckets
Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.
Section
Part 7
Concept
When a result is wrong (but not an error), add print() to show a variable's value at key points. Seeing the actual value usually reveals the bug.
Worked example
total = 0
for n in [1, 2, 3]:
total = n
print("debug total:", total)
print("final:", total)The debug prints expose the mistake
Why: total = n (not total += n) overwrites instead of accumulating - the prints show total is 1, 2, 3, not 1, 3, 6.
Read the trace
Why: Verified by execution: final is 3, revealing the bug. The fix is total += n.
| n | debug total |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
Pattern
Step through it
Step through Finding a logic bug one row at a time. What is driving the change, and what would the row after the last one be?
Concept
Find the smallest input that shows the bug (reproduce it reliably), then add prints or comment out lines to narrow where it goes wrong.
Change one thing at a time, and re-run. Guessing randomly wastes time; narrowing finds it.
Intuition
Form a guess ('total is not adding up'), gather evidence (print it), and confirm or rule out. It is small, patient science.
The traceback and a few well-placed prints are almost always enough to catch the culprit.
Section
Part 8
Concept
List related errors in parentheses: except (ValueError, ZeroDivisionError): handles either with one block.
Worked example
for val in ["abc", "0"]:
try:
print(100 / int(val))
except (ValueError, ZeroDivisionError):
print("skipped bad value")Both bad cases are caught
Why: "abc" raises ValueError; "0" causes ZeroDivisionError. The tuple covers both.
Read the output
Why: Verified by execution: skipped bad value, twice.
| val | error | prints |
|---|---|---|
| abc | ValueError | skipped bad value |
| 0 | ZeroDivisionError | skipped bad value |
Blank canvas
Draw it
Draw what One block, two errors just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.
Concept
A finally: block runs whether or not an error happened - use it for cleanup that must always occur.
Explain it
Discussion prompt
Explain finally runs no matter what to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
A finally: block runs whether or not an error happened - use it for cleanup that must always occur.
Explain it to yourself
Discussion prompt
In Cleanup with finally this move is made:
finally always executes
Why is that legal? Name the rule or definition it rests on before you read on.
Hint: If you can only say "because that is what you do", the rule is the thing to go and find.
Answer:
Even if the try had raised, the finally block would still run.
Worked example
try:
print("working")
finally:
print("cleanup runs")finally always executes
Why: Even if the try had raised, the finally block would still run.
Read the output
Why: Verified by execution: working, then cleanup runs.
| block | runs? |
|---|---|
| try | yes |
| finally | always |
Error analysis
Annotate
Walk the callouts on Cleanup with finally. Each one is a place this is easy to get subtly wrong.
Concept
Wrap a risky conversion in a helper that returns a fallback if it fails - turning a crash into a safe default.
Analogy
Discussion prompt
Explain Return a default on failure by analogy to something with no Python Fundamentals in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
Wrap a risky conversion in a helper that returns a fallback if it fails - turning a crash into a safe default.
Worked example
def to_int(s, default=0):
try:
return int(s)
except ValueError:
return default
print(to_int("7"))
print(to_int("x"))Success returns the number; failure returns the default
Why: "7" converts to 7; "x" fails, so it returns 0.
Read the output
Why: Verified by execution: 7 then 0.
| call | returns |
|---|---|
| to_int("7") | 7 |
| to_int("x") | 0 |
Trade off
Comparison matrix
From A forgiving to_int: every row here is a choice with a cost. Fill the returns column, then say which row you would actually pick and what you give up for it.
| call | returns |
|---|---|
| to_int("7") | 7 |
| to_int("x") | 0 |
Intuition
A robust program bends instead of breaking: skip a bad row, ask again, or use a sensible default - rather than crashing on the first surprise.
But only where recovery makes sense. Silent defaults everywhere can hide real problems, so use them thoughtfully.
Counterexample
Discussion prompt
A robust program bends instead of breaking: skip a bad row, ask again, or use a sensible default - rather than crashing on the first surprise.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Pattern
Predict first
The table runs: 10 | yes | 10 · oops | no | 10
In Average, skipping bad entries, given the rows so far: what is the next one — the row where r is 20?
Correct: 20 | yes | 30
| r | counted? | total |
|---|---|---|
| 10 | yes | 10 |
| oops | no | 10 |
| 20 | yes | 30 |
Why: The relationship between the columns, not the individual numbers, is what generates the next row. "oops" raises ValueError, caught and ignored; only 10 and 20 count.
Worked example
raw = ["10", "oops", "20"]
total = 0
count = 0
for r in raw:
try:
total += int(r)
count += 1
except ValueError:
pass
print(total / count)Bad entries are skipped with pass
Why: "oops" raises ValueError, caught and ignored; only 10 and 20 count.
Read the output
Why: Verified by execution: (10 + 20) / 2 = 15.0. pass means 'do nothing and move on'.
| r | counted? | total |
|---|---|---|
| 10 | yes | 10 |
| oops | no | 10 |
| 20 | yes | 30 |
Comparison
Comparison matrix
From Average, skipping bad entries: refill the total column from what you know. The rest of the table is as it appeared.
| r | counted? | total |
|---|---|---|
| 10 | yes | 10 |
| oops | no | 10 |
| 20 | yes | 30 |
Section
Part 9
Pattern
1. Read the LAST line: the type and message
Why: NameError, TypeError, ValueError, etc. - it names the problem.
2. Find the file and line number
Why: The bottom frame shows where it actually failed; jump there.
3. Match the message to the cause
Why: 'not defined' -> typo/quotes; 'concatenate str' -> mixed types; 'invalid literal' -> bad conversion.
4. Fix one thing, re-run
Why: Change the smallest thing that addresses the message, then run again.
Explain it to yourself
Discussion prompt
In When to use try/except this move is made:
Use it for expected, recoverable failures
Why is that legal? Name the rule or definition it rests on before you read on.
Hint: If you can only say "because that is what you do", the rule is the thing to go and find.
Answer:
Bad user input, a missing optional value - things you can respond to.
Pattern
Use it for expected, recoverable failures
Why: Bad user input, a missing optional value - things you can respond to.
Catch the specific type, never bare except
Why: except ValueError, not except: - so real bugs still surface.
If you cannot recover, let it crash
Why: The traceback is more useful than a hidden error.
Real world
Discussion prompt
Outside this lesson: where does Session 12 - Errors & Debugging actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of When to use try/except is doing the work in it.
Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.
Answer:
Session 12 of the Python Fundamentals series, in depth. Stop fearing the red text: read a traceback from the bottom up; recognize the common errors (NameError, TypeError, ValueError, IndexError, KeyError, ZeroDivisionError, SyntaxError, IndentationError) and their exact messages; guard risky code with try/except, catch specific error types, capture the message with 'as e', validate input in a loop; and debug by printing values, reproducing, and narrowing.
Check
What error is this?
print(int("12x"))| code | error type |
|---|---|
| int("12x") | ? |
Check your understanding
Which error does this raise?
Answer: A
Why: int() received a string of the right type but with non-numeric characters, so it raises a ValueError (invalid literal). Verified by execution.
Elimination
Eliminate the wrong options
Which line do you read first to know what went wrong?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: The last line names the error type and reason - the fastest way to understand the failure. Then work upward to the failing line. Verified by how Python formats tracebacks.
Check
A traceback prints several lines.
# Traceback (most recent call last):
# File ..., line 4, in <module>
# File ..., line 2, in greet
# NameError: name 'naem' is not defined| read order | line |
|---|---|
| first | ? |
Check your understanding
Which line do you read first to know what went wrong?
Answer: A
Why: The last line names the error type and reason - the fastest way to understand the failure. Then work upward to the failing line. Verified by how Python formats tracebacks.
Check
The user types letters.
try:
n = int(input())
except ____:
print("try again")| int on letters raises | so catch |
|---|---|
| ValueError | ? |
Check your understanding
What should fill the blank?
Answer: A
Why: int() on non-numeric text raises ValueError, so that is the type to catch. Verified by execution.
Check
Trace the path.
try:
x = int("5")
print("a")
except ValueError:
print("b")
print("c")| int("5") | path |
|---|---|
| works | ? |
Check your understanding
What does this print?
Answer: A
Why: int("5") succeeds, so the try block prints a and the except is skipped; then c prints after. Verified by execution.
Check
There is a typo: prnt instead of print.
try:
prnt("hi")
except:
print("something went wrong")| real bug | hidden? |
|---|---|
| NameError (prnt) | ? |
Check your understanding
Why is this bare except a problem?
Answer: A
Why: prnt is undefined (NameError), but the bare except catches everything and prints a vague message, hiding the real typo. Catching NameError-level bugs like this makes debugging harder. Verified by reasoning about bare except.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — Errors Are Normal · Reading a Traceback · The Usual Suspects · Handling: try / except · Guarding Input · Handling Carefully. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
Read tracebacks bottom-up, recognize the common errors, and guard expected failures with try / except on a specific type.
| Message hint | Likely cause |
|---|---|
| name ... is not defined | typo, missing quotes, used-before-set |
| can only concatenate str | mixed str and number |
| invalid literal for int() | converting non-numeric text |
| list index out of range | index past the end |
| KeyError | missing dict key |
| division by zero | divided by 0 |
Debug by printing values, reproducing, and narrowing. Next session we start the capstone: planning and building a multi-room adventure game.
Want this taught 1-on-1? Alexander tutors Python Fundamentals — $55/session, free consultation.