Python

Verified against Claude Code · 2026-07-29

Get Python code reviewed for idiomaticity, not just correctness

A review prompt that separates "is this correct" from "is this how an experienced Python developer would write it," with a closed set of idiom categories so the review surfaces real foot-guns instead of restating the code.

Claude CodeChatGPT (GPT-5.1)GitHub Copilot ChatCursor 2.14 fillable variables

The prompt

Ready to copy — highlighted parts are example details you can swap.

Review this code for idiomaticity — assume it already works. Your job is to say where it doesn't read like Python an experienced developer would write, and why the idiomatic version is actually better, not just different or shorter.

CODE
def get_config(name, cache={}):\n    if cache.get(name) == None:\n        cache[name] = load_from_disk(name)\n    return cache[name]

TARGET PYTHON VERSION
3.12 — flag anything that's idiomatic for an older version but has a cleaner equivalent available now (e.g. pre-3.10 code that could use structural pattern matching, or manual dict-default handling that could use dict.setdefault, defaultdict, or the walrus operator where it genuinely improves clarity rather than just being clever).

STYLE GUIDE
follows Black formatting and Ruff's default rule set; no third-party lint config beyond that

TEAM CONTEXT
A team of mostly backend Java developers new to Python; prefer explicit code over dense one-liners.

REVIEW CATEGORIES
1. Pythonic idioms — list, dict, or set comprehensions where a manual loop is just building a collection; enumerate or zip instead of manual indexing; context managers for anything with cleanup; pathlib.Path instead of os.path string joining.
2. Truthiness and comparisons — "if not x" versus "if x is None" used correctly, since they are not interchangeable for empty collections versus None; "is" and "is not" for None and singleton checks; never "== None".
3. Mutability bugs — mutable default arguments, accidental aliasing, modifying a list while iterating over it.
4. Error handling style — specific exception types over a bare except with no type, using exceptions for genuinely exceptional cases rather than control flow, not catching and re-raising without adding information.
5. Naming and structure — does a function do one thing; is a "utils" grab-bag hiding what should be several named functions.
6. Iteration and laziness — a generator or itertools-based approach where the code builds a full intermediate list just to iterate over it once and discard it; unnecessary calls to list() or sorted() on something that only needed to be iterated once.

OUTPUT FORMAT
For each finding: category, the line or snippet, what's non-idiomatic about it, the idiomatic rewrite, and one sentence on why it's actually better, not just shorter. If a "clever" one-liner would be less readable than the original, say so explicitly and leave it — idiomatic doesn't mean maximally compact. Weigh every finding against A team of mostly backend Java developers new to Python; prefer explicit code over dense one-liners. — a rewrite that's more idiomatic in isolation but harder for this specific team to maintain is a finding worth flagging as optional, not mandatory.
End with a verdict: how many findings per category, and whether the code is idiomatic enough to ship as-is or needs the listed changes first, stated plainly enough that a reviewer skimming only the verdict still knows what to do next.

Customize

Optional — swap in your own details for the highlighted parts above.

Why this works

Separating "is this correct" from "is this idiomatic" as an explicit framing keeps the review from defaulting to the most common failure mode of an open-ended "review this" prompt — restating the code's logic back to the requester instead of judging its style. The closed category list forces coverage of specific, well-documented Python foot-guns that a generic review reliably misses, most notably the mutable default argument bug, where a function like def get_config(name, cache={}) shares one cache dict across every call that doesn't pass one explicitly, because default argument values are evaluated exactly once at function-definition time, not per call — a bug that produces correct-looking output for a long time before manifesting as data leaking between unrelated calls. The team_context field matters because "idiomatic" is not a fixed target independent of who maintains the code — a dense, clever one-liner using nested comprehensions might be the objectively idiomatic Python, but for a team of Java developers six months into their first Python codebase, a slightly more verbose and explicit version is the actual right call for that team's velocity, and a review that doesn't weigh this produces technically-correct feedback that would make the codebase harder for its actual maintainers to work in. Requiring "why it's actually better, not just shorter" as a mandatory field directly counters a real failure mode of AI-suggested Python rewrites: compressing readable code into a dense one-liner that a human reviewer would reasonably reject in a real pull request for being harder to follow, not more idiomatic. The explicit permission to leave a comparison unchanged when a compact rewrite would hurt readability stops the review from treating brevity as a proxy for good style. The iteration and laziness category exists because it's a specific, common gap in how models default to writing "correct" Python: building a full list via list comprehension purely to feed it into a for loop once is functionally identical to using a generator expression for anything that doesn't need random access or a second pass, but it forces the whole collection to exist in memory at once for no reason, and a review that never checks for this misses a real, teachable difference between code that merely works and code that reflects an understanding of what Python's iteration protocol is actually for.

What you get back

Finding 1 [Mutability bugs]: cache={} as a default argument — this dict is created once at function definition and shared across every call that doesn't explicitly pass a cache, so entries silently accumulate across unrelated calls. Rewrite: use cache: dict | None = None, then cache = cache if cache is not None else {} inside the function. Mandatory given team_context — this is a correctness bug, not a style preference, regardless of team experience level. Finding 2 [Truthiness and comparisons]: cache.get(name) == None — should be cache.get(name) is None. Mandatory but low-severity; flagged as an easy bundle-in alongside Finding 1. Verdict: 2 findings (1 mutability, 1 comparison), both mandatory. Needs the mutable-default fix before shipping.

Verified against

Claude Code Sonnet 4.6 · 2026-07-29

GitHub Copilot Chat 1.261 (VS Code) · 2026-07-30

Changelog

  • 2026-07-30 Initial publish, verified against Claude Code (Sonnet 4.6) and GitHub Copilot Chat.

Need this built into your business?

If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.

EXPLORE CUSTOM SOFTWARE
All Python prompts

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY