Python from First PrinciplesPost 18 of 20 · 20 of 20 written

18. Asking the right questions

Python · 18 of 202 min readOct 2026

Fluency means knowing which question exposes the problem. Use this part as a checklist whenever you read, review or prompt for code, whether you or an AI assistant wrote it.

Nine questions that cover most bugs

  1. Objects: what does this name point to, who else references it, and is it mutated here? (Part 2)
  2. Types: what type is this value, and which special method does this syntax call? (Parts 3 and 7)
  3. Shapes: what are the shape, dtype and device after each step? (Parts 13 and 15)
  4. Cost: does the time go to the interpreter or to compiled code, and what is the complexity? (Parts 3 and 11)
  5. Waiting: is this I/O-bound or CPU-bound, and does the concurrency model match? (Part 12)
  6. Failure: what happens on a timeout, bad input, partial failure or a crash mid-write? (Parts 8 and 16)
  7. Trust: where does untrusted data enter, and where is it validated? (Parts 10, 14 and 16)
  8. Environment: which interpreter, which package versions, which CUDA build? (Part 9)
  9. Evidence: which test or measurement shows this works? (Parts 11 and 17)

Red flags in AI-written Python

  • except Exception: pass, or broad excepts that quietly return a default.
  • Mutable default arguments, and mutable state at module level.
  • if x: where 0, an empty string or an empty list is a valid value.
  • Blocking calls (requests, time.sleep, sync SDK clients) inside async def.
  • Network calls with no timeout; retries with no backoff; retries stacked on top of an SDK’s own retries.
  • Python loops over array or tensor elements; .item() or .cpu() inside the training loop.
  • pickle.load or torch.load on outside files; eval or exec on model output.
  • API keys, paths and model names hard-coded across files instead of one settings object.
  • Layers kept in a plain list inside an nn.Module; evaluation without model.eval() or torch.no_grad().
  • Invented APIs: methods or parameters that do not exist in your installed version. Check with help() or the docs for that version.
  • Unstated shape assumptions, with no assertions or shape comments.
  • Tests that only cover the happy path, or mock so much that nothing real is tested.

Prompting coding assistants as the architect

  • Specify the contract: inputs, outputs, types, error behavior and performance limits. A function signature or Pydantic model is the clearest spec.
  • State the environment: Python version, library versions, sync or async, CPU or GPU.
  • Ask for tests with the code, including failure cases.
  • Ask what could break it and what it assumes about the inputs, before you accept it.
  • Ask for the smallest change that works, and review diffs rather than whole files.
  • Report failures fully: the complete traceback and exact versions, not a summary.

Turning confusion into a good question

A weak question: “PyTorch training doesn’t work.”

A strong question: “My 10-class MLP’s loss stays at 2.30. I printed named_parameters() and all layers are registered. The order is zero_grad, backward, step, with lr 3e-4. Gradients on fc1.weight are all zero. What could zero the gradients before the first layer?”

The strong version gives the symptom with numbers, says what is already ruled out, and asks one narrowed question. Even the number is a clue: 2.30 is ln(10), the loss of a model that guesses uniformly across 10 classes.