Strings, Files & Errors
- Transform text with the core string methods: strip, split, join, replace, lower, startswith
- Read and write files safely using pathlib and the with statement
- Round-trip Python data through JSON and CSV files
- Handle failures with try/except/else/finally and raise your own exceptions
- Explain EAFP vs LBYL and pick the Pythonic option for a given situation
| Spaced-rep warm-up: Days 1β4 flashcards | 10 min |
| Concept study: ELI5 + tech (files, JSON, exceptions, EAFP) | 20 min |
| Guided: string toolbox, paper trails, JSON round-trip | 45 min |
| Practice: the resilient summer | 20 min |
| Project: the journal goes digital | 15 min |
| Quiz + flashcards | 10 min |
Builds on: Day 2 β Types and control flow Β· Day 4 β Lists and dicts
Everything your programs have made so far lives on a whiteboard: the moment the script ends, the janitor wipes it clean. Variables are whiteboard scribbles. A file is the paper trail β write it down on paper, put it in the filing cabinet (your disk), and it's still there tomorrow, next week, after a reboot. Today your programs learn to leave paper trails: reading files in, writing results out, and using two standard "paper formats" β CSV (a spreadsheet as plain text) and JSON (lists-and-dicts as plain text, the lingua franca of the internet).
The second half is the safety net. A trapeze artist doesn't pretend falls never happen; they hang a net so a fall is an event, not a catastrophe. In Python, things WILL go wrong at runtime β a file is missing, a line isn't a number β and each fall is an exception. try is the trapeze act, except is the net: catch the specific fall you expect, deal with it, and keep the show going. The alternative β checking every possible problem before every move β is exhausting and full of gaps. Often it's easier to ask forgiveness than permission.
Files and errors are where programs meet the messy world, and AI engineering is unusually messy: Day 113's RAG pipeline is "read a pile of files, clean the text, handle the broken ones"; every LLM API call returns JSON and can fail mid-flight (Day 107's whole lesson is retrying those failures gracefully). FDEs feel it hardest β customer data is never clean, and the difference between a demo that dies on row 3 and one that reports "skipped 3 malformed rows" is the difference between losing and keeping the room. Exception discipline β catch specifically, fail loudly, never bare-except β is a hiring signal all by itself.
Guided practice
The string toolbox β clean a messy roster
15 min- Create
week-01/strings_lab.pywith the starter code β a messy roster of "name, score" lines with stray spaces and inconsistent case, as if pasted from a spreadsheet. - Run the cleaning pipeline and inspect each intermediate print. For the first line, write the value after each method in a comment: raw -> stripped -> split -> each piece stripped.
- The chain line.strip().split(",") works because each method RETURNS a new string. Prove immutability in the REPL: s = "hi"; s.upper(); print(s) β s is unchanged until you rebind.
- Add a check that skips lines that don't contain a comma (use "," in line) and count how many were skipped.
- Finish by rebuilding output with join: one line "ada, grace, alan" from the cleaned names. Remember join hangs off the SEPARATOR string.
Paper trails β write, read, append with pathlib
15 min- Create
files_lab.pywith the starter code and run it TWICE. Before the second run, predict: how many lines will log.txt hold? (The append mode is the key.) - Open log.txt in VS Code and confirm. Now change "a" to "w", run twice more, and see the difference β "w" truncates on every open. Write the rule in a comment: w wipes, a appends.
- The with block is the safety guarantee: the file closes even if the code inside crashes. Prove the loop-over-file pattern: read the file back line by line, stripping each line (every line arrives with its newline attached).
- Use Path.glob to list every .py file in your week-01 folder β your first taste of filesystem automation.
- In a comment: why is for line in f better than f.read() for a 10 GB file? (Day 11 makes this rigorous.)
JSON round-trip with a safety net
15 min- Create
json_lab.pywith the starter code. It saves your Day 4 study-log shape to disk and loads it back β your first real persistence. - Run it, then open studylog.json and admire the format: it IS your list of dicts, as text. Change a value in the FILE by hand, rerun, and watch Python see your edit β the paper trail is real.
- Now the safety nets. Delete studylog.json and rerun: the FileNotFoundError branch supplies a fresh empty log instead of crashing. This try/except-returns-default shape is the standard "first run" pattern.
- Break the JSON on purpose (delete a comma in the file) and rerun: the JSONDecodeError branch catches it. Note how each except names ONE specific failure with its own response.
- Add validation with raise: in add_entry, raise ValueError if minutes is negative. Trigger it once, read your own traceback, then wrap that call in try/except to handle it. You have now been on both ends of an exception.
On your own
The resilient summer
20 minBuild sumfile.py from scratch.
Goal: first, write a small setup block (or separate script) that creates numbers.txt containing one value per line β mostly numbers, but include junk: an empty line, the word "twelve", a number with spaces around it. Then write sum_file(path) that reads the file and returns a tuple (total, good_count, bad_count), skipping unparseable lines without crashing. Print a report: total, lines counted, lines skipped.
Constraints: use EAFP β try float(line) and catch ValueError; no checking line contents with if-tests first. Handle a missing file with its own except that prints a helpful message and exits cleanly. Use with open everywhere.
Hints (only if stuck): strip each line before converting; an empty string raises ValueError too, which is exactly what you want. Tuples return multiple values: return total, good, bad.
The journal goes digital
Upgrade your paper-trail habits: build journal_tool.py, a small program that manages journal entries in journal.json. Running it appends one entry: it asks for today's summary line with input(), stamps it with the date (toolbox.py's today_stamp β import your own module!), and saves. Before appending it must load existing entries, surviving both a missing file and a corrupt file (each with its own except and message). After saving, it prints all entries oldest-first, formatted "2026-08-11 β summary text". Use it for real: add today's entry. From now on, this is your journal. On Day 7 you will reuse this exact load/save pattern for the task tracker.
Common mistakes & misconceptions
- Opening with "w" when you meant "a". Write mode truncates the file the instant it opens β the classic way to delete your own data. Append for logs and journals; write only for full rewrites.
- Forgetting that every line read from a file ends with a newline character. Compare or convert without .strip() and "42\n" ruins your day. Strip first, always.
- Using a bare except: β it silently swallows typos (NameError), Ctrl+C, everything. Catch the specific exception you expect; let the rest crash loudly so you can fix them.
- Catching an exception just to pass. Silent failure is worse than a crash: the program lies about being fine. At minimum, print or log what happened and count it.
- Building CSV by hand with .split(",") / string concatenation. Quoted fields with embedded commas break both directions. Use the csv module β DictReader/DictWriter.
- Expecting json.load to preserve tuples or datetime objects. JSON only knows objects, arrays, strings, numbers, booleans, null β tuples come back as lists, dates must be stored as strings.
Q1. Why is "with open(path) as f:" preferred over f = open(path)?
Q2. Which is the EAFP way to parse user input as an int?
Q3. You json.dump a dict, then json.load it back. What do you get?
Go deeper β curated resources
- What is an encoding, really? β UTF-8 maps every character to 1β4 bytes and dominates the web. Skim the Unicode HOWTO in the Python docs once; you mostly just pass encoding="utf-8" and move on. Tokenizers (Day 96) revisit bytes-vs-characters with money on the line.
- All three guided scripts run; the w-vs-a experiment and both broken-file recoveries demonstrated
- sumfile.py returns correct (total, good, bad) on a file with junk lines
- journal_tool.py used for a real entry; runs twice without data loss
- Quiz β₯ 2/3 (reread the exceptions section if you missed 1 or 2)
β Back: The list-of-dicts you designed on Day 4 just became a FILE β json.dump/load is the bridge. The line-cleaning pipeline is Day 2's string knowledge industrialized, and every safety net catches the same exceptions you have been reading since Day 1.
Forward β: Day 7's task tracker is today's journal pattern with more commands. Day 11 turns for-line-in-f into full lazy pipelines; Day 13 adds regex to the text toolbox; Day 16 replaces print-debugging with real logging. And every API you call from Day 41 onward speaks the JSON you round-tripped today.
Unlocks: D6 The Terminal & Linux Β· D7 Week 1 Checkpoint: CLI Task Tracker Β· D11 Iterators & Generators Β· D13 Regex & Text Processing