The problem
You opened a file. There's a function. It's four lines long, it has no comments, the author left the company in 2023, and you have no idea what it does. Git blame says it hasn't changed in two years, which means either it's perfect or everyone else is also afraid of it.
You need to change the thing it touches. But you can't change code you don't understand without rolling dice. So you do the thing everyone does: you stare at it, you trace one variable by hand, you give up, you ask in Slack, nobody answers, and you ship around it instead of through it.
This is the single highest-leverage thing an LLM does for a working programmer, and most people use it badly. They paste the code, type "explain this," get a paragraph that restates the code in English, and learn nothing. The trick is asking for the things you actually can't see: the language feature being abused, the assumptions, and what breaks.
When to use this β and when not to
Use it when:
- You inherited a function and need to modify or call it safely.
- The code uses a language feature you half-recognize (a sentinel, a metaclass, a bit-twiddle, a clever
reduce). - You're reviewing a PR and something looks too clever to trust.
- You're learning a codebase and want the "why," not just the "what."
Don't use it when:
- The behavior is the question, not the code. If you need to know what it does at runtime with your data, run it. An LLM reasons about the source; it does not execute it. A print statement is cheaper and certain.
- The code is security-sensitive and the explanation would be load-bearing. Verify the LLM's claim against the docs before you trust "this is safe."
- It's genuinely trivial. You don't need a model to explain a getter. Reading is faster.
The failure mode to watch: a confident, fluent explanation that is subtly wrong. Fluency is not correctness. The recipe below is built to make wrongness easier to catch.
The recipe
Paste the function. Add the surrounding context if you have it (the file's imports, the caller). Then use this prompt verbatim:
You are explaining code to an engineer who has to modify it and cannot
afford to be wrong. Here is the code:
<paste code here>
Walk through it in this exact order:
1. ONE sentence: what is this for? (the job, not the mechanism)
2. Line by line, what each line does. Call out any language feature,
idiom, or trick that a competent dev might not recognize β name it
explicitly (e.g. "this is the two-argument form of iter()").
3. The assumptions it makes about its inputs that are NOT checked in
the code. What must be true for it to work?
4. Edge cases and inputs that would break it or behave surprisingly.
5. One concrete rename or comment that would make it self-explanatory.
Rules: if you are unsure about any line, say "I'm not sure" instead of
guessing. Do not restate the code in prose β explain the parts I can't
see by reading it. Be concise.The "name the trick explicitly" line is what turns a useless answer into a useful one. The "if unsure, say so" line is what keeps it honest about the lines it's bluffing on.
A worked example
(This is output I got running the recipe, lightly trimmed. It is not a captured or independently verified run β the proof system that would back that claim isn't wired up yet. Treat it as a representative example, not evidence.)
The function I fed it β a real one that has confused real people:
from itertools import islice
def f(seq, n):
it = iter(seq)
return iter(lambda: tuple(islice(it, n)), ())The ugly first attempt. Before the recipe, I just typed "explain this code." Here's what that got me:
This function takes a sequence
seqand a numbern. It creates an iteratoritfrom the sequence, then returns an iterator that produces tuples by slicingnitems at a time. It's a way to iterate over the sequence in groups.
Technically true. Completely useless. It told me the part I could already read and skipped every part I couldn't β why it returns an iterator of an iterator, what () is doing there, when it stops. I still couldn't safely touch it.
With the recipe:
1. What it's for: It splits an iterable into consecutive chunks of size
n(the last chunk may be shorter). It's a lazychunked()/batched().2. Line by line:
it = iter(seq)β gets a single shared iterator. Important: shared. Every call to the lambda pulls from the sameit, so progress is preserved across calls.iter(lambda: ..., ())β this is the two-argument form ofiter(), the part most people don't recognize.iter(callable, sentinel)callscallable()repeatedly and stops when the result equalssentinel. Here the sentinel is the empty tuple().tuple(islice(it, n))β pulls the nextnitems off the shared iterator and packs them into a tuple. Whenitis exhausted,isliceyields nothing, so this returns()β which equals the sentinel, so iteration stops.3. Unchecked assumptions:
n >= 1. Ifnis0,islice(it, 0)always returns()immediately, which equals the sentinel, so you get an empty result even for a non-empty input β silent wrong answer, no error.seqis finite, or you only consume the result lazily. On an infinite generator it works lazily but will never end if you calllist()on it.4. Edge cases:
- Empty
seqβ yields nothing. Fine.n=0β yields nothing regardless of input. Bug-prone.- Negative
nβisliceraisesValueError. Loud, so okay.- The last chunk is shorter than
n. Callers that assume every chunk is exactlynlong will break.5. Rename/comment: Rename
fβchunked,seqβiterable,nβsize. Add:# uses iter(callable, sentinel): repeatedly takesizeitems until islice returns an empty tuple.
That last section is the payoff. I came in wanting to change the caller; I left knowing the two real traps β n=0 returns a silent empty result, and the short final chunk β neither of which is visible in four lines of code.
I spot-checked the n=0 claim in a REPL because it was the surprising one. It's right. That five-second check is the whole game: the model points you at what to verify, you verify the load-bearing claim, you don't verify the obvious stuff.
Where it breaks
It explains what the code should do, not what your fork actually does. If someone patched this function in a way the model has never seen, it'll explain the idiomatic version and miss your local weirdness. Patch: paste the exact current code including any surrounding decorators and the imports, and add "explain THIS code, not the standard version of this pattern."
Confident hallucination on obscure APIs. For a well-known idiom like the iter() sentinel, models are reliable. For a rare library call or a language version quirk, the explanation can be fluent and wrong. Patch: the "if unsure, say so" rule catches some of it; for the rest, treat any claim you're about to rely on as a hypothesis and check it against the docs or a REPL. The recipe's job is to tell you where to look, not to be the final authority.
It infers intent it can't actually know. "This is for batching API requests" might be a guess dressed as a fact. Patch: read section 1 as "plausible purpose," not gospel. The mechanism (sections 2β4) is grounded in the code; the purpose is inference.
Huge functions blow the useful-context budget. A 300-line function gets a 300-line shrug. Patch: don't paste the whole thing. Paste the 20 lines you actually need to touch plus the function signature, and ask specifically about those.
It misses the cross-file contract. The function might be safe only because of an invariant enforced three files away. The model can't see that file. Patch: if the explanation says "assumes X about the input," go find who guarantees X. That's a feature β it surfaced an assumption you now know to chase.
Cost & time
About 600β900 tokens in, 500 out. On current mid-tier models that's well under a cent β call it ~$0.01. On a free chat tier it's free.
Maybe 10 minutes end to end: one minute to paste and prompt, a few to read, and the rest spent verifying the one or two claims you're going to lean on. Compare that to the half-day you'd lose tracing it by hand, or the silent bug you'd ship by guessing. The model doesn't replace understanding the code β it just gets you to the understanding an hour faster, and tells you which assumption to go check before you bet on it.