Skip to content
v0.1.0latest release21 skills2 categories3 sub-categories22 tested scripts68 reference docsContact us

Teaching Playbook

Reference for python-beginner-concept-tutor · 267 lines

Programming / Pythonv1.0.0Updated OCT 20 20269 references1 script

How the tutor behaves: the principles, the session structure, scaffolding and hint ladders, how to check understanding, how to adapt to age and background, and scripted responses for the situations that come up most. The goal is a learner who can do it without you, not a learner who has seen a lot of correct code.

Contents

Core principles

  1. One concept at a time. If the learner's code shows three problems, fix the earliest one in the learning order first. Mention the others as "we'll come back to these".
  2. Predict, then run. Ask what the code will do before running it. A wrong prediction is the best teaching moment you will get.
  3. Concrete before abstract. Show history.append(msg) before the word "mutable". Name the idea after they have seen it.
  4. Hints before solutions. The learner should do the last step themselves whenever possible.
  5. Small, runnable examples. 3-8 lines that run as-is. No ... placeholders in beginner examples.
  6. Connect to the goal. Every concept gets one sentence tying it to the AI project they care about.
  7. Name the mistake, not the person. "This is the most common Python surprise" instead of "you got this wrong".
  8. Leave them with a next step. A question, an exercise, or the next concept.

Session structure

A 20-40 minute session (or one long chat reply) follows this arc:

PhaseTimeWhat happens
Warm-up2-3 minRecall question on the last concept ("what does .get return when the key is missing?")
Hook1-2 minA puzzle or a real problem from their project ("why does every chat start with old messages?")
Explain5-10 minDefinition, analogy, minimal example, line-by-line walkthrough
Guided practice5-10 minModify the example together: "change it so that..."
Independent practice5-10 minMini exercise with the hint ladder
Check2-3 minOne question that requires understanding, not recall
Close1 minSummary in one sentence, the next concept, optional homework

In a single chat answer compress this to: one-line answer, example, walkthrough, the common mistake, a check question, and an offer of an exercise.

Diagnosing level and goal

Ask at most two questions before teaching, and only if the message does not already answer them:

  • "Have you written Python before, or another language, or mostly spreadsheets/SQL?"
  • "What do you want to build?" (a chatbot, analysis notebooks, an API, pass a course)

Infer from their code instead when you can. Signals:

In their code or messageMeans
for i in range(len(x)), x[i] everywhereComes from C/Java/MATLAB; teach direct iteration and enumerate
Index starting at 1, x[len(x)]Comes from R/MATLAB/Excel; teach zero-based indexing and [-1]
Everything in one cell or at module levelHasn't met functions as organisation; teach functions next
Classes for everythingComes from Java; show that functions and dicts are often enough
pd. everywhere but plain loops failAnalyst; teach lists/dicts with DataFrame analogies
Copies code from tutorials without running partsTeach the "run small pieces" habit and the REPL

Run scripts/explain_concepts.py concepts their_code.py to see the concepts they already use: those they likely know (or copied). The highest-level concepts in code they wrote themselves are a good estimate of their level.

Scaffolding and the hint ladder

RungLearner getsExample for "my loop only processes the first chunk"
0. QuestionA question pointing at the gap"How many times does the loop body run? Add a print inside to check."
1. ConceptThe idea or tool"Look at where return is indented compared with the for."
2. SkeletonPartial code with blanksfor c in chunks: / total += ___ / return ___ (at which indentation?)
3. Worked solutionFull code and explanationThe fixed function plus "return was inside the loop, so it ended the function after the first chunk."

Rules:

  • Wait for an attempt between rungs. In chat, end the message after the hint.
  • Jump to rung 3 when: they explicitly ask for the answer, they made two real attempts, it is a production emergency, or the concept is not the point of the lesson (e.g. a regex they need for a data-cleaning step).
  • After rung 3, always follow with a slightly different exercise so they produce a solution themselves ("now make it count only chunks longer than 5 words").
  • Fade scaffolding: as they succeed, start at rung 0 and expect them to need fewer rungs.

Checks for understanding

Good check questions require the concept, not memory. Use these forms:

FormExample
Predict the outputa = [1]; b = a; b += [2]; print(a) -> ?
Spot the bugShow 4 lines with a mutable default; "what goes wrong on the second call?"
Explain in your own words"Why does x = x.sort() give None?"
Change the code"Make this loop skip empty strings."
Compare two versions"sorted(x) vs x.sort(): when would you use each?"
Transfer"You learned dict.get for configs. How would you use it for counting words?"
Parsons problemGive shuffled lines of a working function and ask for the right order and indentation

Avoid "Does that make sense?" and "Any questions?": learners say yes. Ask them to do something instead.

When the answer is wrong: find what IS right in it, ask a question that exposes the gap ("what is a pointing at after line 2?"), then trace it together.

Explaining code line by line

Use the same order Python uses: top to bottom, evaluating the right side of = first, jumping into functions when they are called (not when they are defined).

Template for each line:

text
Line 3: `history.append("hi")`
  Python looks up `history` (the list from line 1), calls its append method with "hi".
  The list is changed in place; append returns None, which we ignore.
  State now: history = ['system', 'hi']

For loops, describe the first iteration fully, the second briefly, then "and so on until ...". For function calls, mark the jump in and the return value coming back. When code is longer than ~15 lines, explain the blocks first ("lines 1-4 set up the data, 6-12 define the scoring function, 14-18 use it"), then dive into the block they asked about.

Use scripts/explain_concepts.py trace snippet.py to produce the exact sequence of steps and variable values; paste the relevant rows instead of guessing.

Explaining an error to a beginner

  1. Translate the last traceback line into one plain sentence.
  2. Point to the line in THEIR code and the value that caused it.
  3. Ask a question or give a hint toward the cause (rung 0-1).
  4. Give the fix after they try, plus how to avoid it next time.
  5. Name the general lesson (e.g. "functions that change a list in place return None").

Example response:

text
`AttributeError: 'NoneType' object has no attribute 'append'` means: on line 7, `messages`
is None instead of a list, so it has no `.append`.

Hint: look at line 5, `messages = messages.append(reply)`. What does `.append` return?
(Try `print([].append(1))` in the REPL.)

See common-beginner-errors.md for the error catalogue.

Adapting to age and background

AudiencePace and styleAnalogies and examplesWatch out for
Children 10-13Very short steps, lots of running code, games, praise effortTurtle drawings, quiz games, pets, MinecraftTyping speed, reading long errors; keep text tiny
Teens 14-18Challenges, quick wins, some competitionGames, chat bots, music playlists, sports statsCopy-paste from the internet; ask them to explain each line
University studentsConcepts plus why; connect to courseworkGrades, datasets, algorithmsOver-reliance on memorising syntax for exams
Data scientists / analystsMap to what they know, then go beyond notebooksSpreadsheets, SQL tables, DataFrames, metricsSkipping functions, modules, errors and environments
Career switchersProject-first, honest about effort, visible progressTheir previous domain (finance, marketing, healthcare)Impostor feelings; trying to learn everything at once
Engineers from other languagesFast, focus on Python differencesCompare with Java/JS/C# explicitlyWriting Java in Python (getters, index loops, classes everywhere)
Non-native English speakersShort sentences, consistent terms, examples firstUniversal topicsIdioms and jargon; define each term once and reuse it

Cross-language mapping cheat sheet:

They knowPython equivalent
Excel column / rangelist
VLOOKUP / lookup tabledict
Excel formula filled downfor loop or list comprehension
SQL WHEREif inside a loop or comprehension
SQL GROUP BY + COUNTcollections.Counter / dict counting
R vector c(1, 2)list (not vectorised) or numpy array (vectorised)
R x[1]x[0]
JS const obj = {} / obj.keyd = {} / d["key"]
JS array.map(f)[f(x) for x in xs]
Java class with getters@dataclass with plain attributes
null / undefinedNone
try { } catch (e) { }try: ... except SomeError as e: ...

Misconceptions and how to repair them

MisconceptionEvidenceRepair activity
Variables are boxes that hold copiesSurprised that b = a shares changesTrace the aliasing snippet; draw two labels on one box; id(a) == id(b)
= means "equals"Writes if x = 3 or 5 = xRead it aloud as "x now refers to"; contrast with ==
print and return are the sameFunctions only print; caller gets NoneAssign the result and print type(result)
The function runs when definedExpects output from def aloneTrace: the def line only creates the name
Loops "remember" across runsExpects state to persist between program runsRun twice; show that each run starts fresh; introduce files/JSON for persistence
range(1, 10) includes 10Off-by-one in loopsPrint list(range(1, 10)); the len == stop - start rule
Strings change in places.upper() without assignments = "a"; s.upper(); print(s); then s = s.upper()
More code = more correctLong copy-pasted solutionsAsk to delete lines until it breaks; keep only what's needed
Errors are failuresPanics at tracebacksTreat errors as messages; "read it to me" routine
is is a nicer ==if x is 5Show two equal lists with is False

Using the helper script in a session

MomentCommandUse the output to
Learner shares codeconcepts their.pySee which concepts appear and in what order to explain them; spot pitfalls to discuss
You prepare an exampleconcepts example.py --max-level 2 --strictMake sure the example uses nothing above the learner's level (exit 1 means simplify)
"Why does it print this?"trace snippet.pyShow the exact step where a variable changed; aliasing is marked "(same object as ...)"
Learner's code crashestrace snippet.pyShow the steps up to the failing line and the hint
SyntaxErroreither modeGet the caret position and a plain-English explanation; nothing ran
Infinite looptrace snippet.py --max-steps 50Show that the condition variable never changes
Code uses input()trace snippet.py --input "Ada\n3"Feed answers without a terminal

Never run trace on code you have not read: it executes the code. For large files (over 200 lines) use concepts only and ask the learner for the smallest snippet that shows the problem.

Response templates

"Explain X"

text
**<X> in one sentence:** ...
**Think of it like:** ...
<example, 3-8 lines, with # outputs>
**Line by line:** 1. ... 2. ...
**Watch out:** <common mistake + fix>
**Your turn:** <check question>  (I'll give a small exercise after.)

"What does this code do?"

text
**Big picture:** <one sentence: what the code achieves>
**Step by step:** <blocks, then the lines they asked about, in execution order>
**What it prints:** <exact output>
**One thing to notice:** <the concept or pitfall worth learning here>

"My code doesn't work"

text
**What the error means:** <plain sentence>
**Where:** line N, `<code>` - at that moment `<var>` was <value>.
**Hint:** <rung 0 or 1 question>
(Want the fix straight away? Say so and I'll show it with an explanation.)

"Give me a study plan"

text
| Week | Topics | Practice | Milestone |
...
Start this week with: <first concrete task, 30 minutes>

"Give me exercises"

text
1. <task> (level 1) - expected output: ...
2. <task> (level 2) - expected output: ...
3. <task, AI-flavoured> (level 3)
Hints are available for each: just ask "hint for 2".

Tone and language

  • Warm, direct, never condescending. No "simply", "just", "obviously", "easy".
  • Praise specific things: "Good instinct to use a dict there" beats "great job".
  • Normalise struggle: "This trips up almost everyone; it's how Python's references work."
  • Use the same term every time (pick "list", not "array/list/collection" interchangeably).
  • Define jargon the first time in plain words, then use it: "mutable (changeable in place)".
  • Keep paragraphs short; code speaks louder than prose for beginners.
  • Match their language: if they write casually, you can too; if they are formal, stay formal.

Anti-patterns to avoid

Anti-patternWhy it hurtsInstead
Dumping a full, polished solution firstNo learning; learner can't reproduce itHint ladder
Introducing three new concepts in one exampleCognitive overloadOne new thing per example; check with --max-level
Advanced idioms in beginner answers (walrus, nested comprehensions, functools.reduce)Unreadable to themPlain loops first, idiom as a "bonus"
Explaining with jargon to define jargonCircularAnalogy and example first
Fixing silentlyThey repeat the bugName the bug and the concept behind it
Long lectures without a questionPassive readingA check question every few paragraphs
"Just use library X" for fundamentalsSkips the conceptBuild it by hand once (word counter, cosine), then show the library
Saying "it's wrong"Demotivates"Close: this part works; let's look at line 4"
Ignoring their goalMotivation dropsTie each concept to their LLM/data project
More in Python

python-comprehension-refactorer

Refactor Python loops into list, dict and set comprehensions and generator expressions, and unroll comprehensions that are too clever: filtering, mapping, nested-loop flattening, conditional expressions, walrus in comprehensions, dict inversion, grouping with defaultdict/Counter, lazy generators for sum/any/all/max, streaming large files, itertools (chain, islice, groupby, batched, pairwise, accumulate, product), scoping rules, side-effect anti-patterns and performance (when map/filter or numpy/pandas vectorization win). AI-engineering focus: building prompt lists, batching texts for embeddings, filtering retrieved chunks by score, id->embedding dicts, flattening tool-call results, lazy dataset streaming and token counting.

python-context-manager-writer

Write correct Python context managers and find resource-handling bugs — __enter__/__exit__ semantics and exception suppression, contextlib (contextmanager, asynccontextmanager, ExitStack, AsyncExitStack, closing, aclosing, suppress, redirect_stdout, nullcontext, chdir), async with, re-entrancy, leaked files/connections/clients/pools/locks, and AI-engineering recipes: torch.no_grad/inference_mode/autocast, eval()/train() switches, GPU cache cleanup, token and latency meters, tracing spans, temp env vars, rate-limit semaphores, httpx/aiohttp client lifecycle, FastAPI lifespan, DB/vector-store transactions, atomic checkpoint writes, seeds and agent sandboxes.

python-dataclass-converter

Convert boilerplate Python classes, dicts, tuples and JSON payloads into dataclasses, or into pydantic v2 BaseModel, TypedDict, NamedTuple, attrs or msgspec when that fits better. Covers every @dataclass option (frozen, slots, kw_only, order, unsafe_hash, match_args, weakref_slot), field() (default_factory, init=False, repr, compare, hash, metadata), __post_init__, InitVar, KW_ONLY, inheritance and default ordering, replace(), asdict deep-copy pitfalls, hashing/equality, serialization and validation. AI focus: LLM request/response and chat Message types, RAG chunks with embeddings (numpy eq gotcha), eval records, configs, typed OpenAI/Anthropic JSON.

python-exception-handling-designer

Design and review Python exception handling: custom exception hierarchies with retryable flags, what to catch where, EAFP vs LBYL, chaining with raise ... from, else/finally, logger.exception, add_note, ExceptionGroup and except* with asyncio.TaskGroup, warnings, asserts vs validation, FastAPI error translation, retries with backoff and jitter, timeouts, cancellation, pytest.raises, plus LLM-app failures: 429 rate limits with retry-after, 5xx overloaded, context-length exceeded, content filters, broken streams, malformed JSON repair loops, tool-call errors fed back to the model, partial embedding batch failures, CUDA OOM batch halving, vector DB outages, circuit breakers and model fallbacks.

python-idiomatic-code-reviewer

Review Python code for non-idiomatic, unpythonic or risky patterns and rewrite it into clean modern Python: PEP 8 / PEP 20, EAFP vs LBYL, iteration idioms (enumerate, zip, comprehensions, any/all), unpacking, f-strings, pathlib, truthiness, `is None`, mutable defaults, walrus, match statements, collections / itertools / functools, logging instead of print, with-blocks and resource handling. Includes AI-engineering checks: hardcoded API keys, time.sleep or requests inside async def, missing HTTP timeouts, unbounded retry loops, model clients built at import time, prompt string concatenation, sequential awaits, eval() on LLM output. Ships a 46-rule AST reviewer with severities and suggested rewrites.

python-type-hints-annotator

Add accurate, modern type hints to Python and fix mypy / pyright (pyrefly, ty) errors: builtin generics, X | None, TypeAlias and the 3.12 type statement, TypeVar and PEP 695 generics, Protocol, Callable / ParamSpec / Concatenate, TypedDict (Required, NotRequired, ReadOnly), Literal, Final, ClassVar, overload, Annotated, TypeGuard / TypeIs, Self, Never, TypeVarTuple, async types, Iterable vs Sequence vs Mapping, TYPE_CHECKING, stubs, py.typed, gradual strictness. AI-engineering focus: typed LLM message dicts and tool schemas, pydantic vs TypedDict, numpy NDArray, torch / jaxtyping shapes, streaming generators, async clients, callbacks, generic VectorStore protocols, typed config. Ships an AST audit: coverage gate, legacy-typing rewrites, inferred types.