Python Style Rules
Ordered by how much damage breaking them does.
Failures must be visible
- Never write a bare
except:orexcept Exception:that continues. It catches the typo in the line above it too. Catch the specific exception you expect. - Never swallow an exception silently. If ignoring it is right, log it or comment why in one line.
- Do not return
Noneto signal an error in a function that also returnsNonelegitimately. Raise, or return an explicit result type. - Chain exceptions.
raise X from err. Dropping the cause discards the traceback that explains the failure. - Validate at the boundary. Data from a network, a file, or a subprocess is untrusted. Check it once on the way in, not defensively at every use.
The obvious traps
- No mutable default arguments.
def f(x=[])shares one list across every call. UseNoneand build inside. - Do not mutate a collection you are iterating. Build a new one.
- Close what you open. Use
with, always, including for subprocesses and locks. - Compare with
isonly forNone,True,False. Not for strings or numbers. - Beware truthiness on containers and numbers.
if not countis true for zero. Sayif count is Nonewhen that is what you mean.
Types and data
- Type hints must be honest. If it can return
None, the hint says| None. A wrong hint is worse than none, because tools trust it. - Prefer a dataclass or NamedTuple to a dict for anything with a fixed shape. A dict of known keys is a class that has not admitted it yet.
- Do not use a tuple with more than three elements as a return value. Name the fields.
Dependencies
- Do not add a dependency for something the standard library does.
pathlib,json,itertools,dataclasses,subprocesscover an enormous amount. - Do not add a dependency for one function. Copy the twenty lines, with credit.
- Pin what you add, and say in the commit why it is needed.
Structure
- Functions do one thing and are named after it. A name with
andin it is two functions. - No side effects at import time. No network calls, no file writes, no environment mutation in module scope. Import must be free.
- Match the file you are editing. Its conventions win over your preferences.
Comments
- Comment the why. The constraint, the workaround, the reason for the odd choice.
- Docstring the contract, not the implementation: what it takes, what it returns, what it raises.
- Delete commented-out code.
What good looks like
python
# The vendor API returns 200 with an empty body on rate limit, so a status# check is not enough to tell success from throttling here.try: payload = json.loads(response.text)except json.JSONDecodeError as err: raise UpstreamError(f"non-JSON body from {url}") from errSpecific exception, cause preserved, and a comment explaining something the reader could not have guessed from the code.