Python Best Practices
A closing checklist of habits -- style, structure, and tooling -- that separate working Python from good Python.
3 min read
Python code that runs correctly and Python code that's pleasant to maintain are not automatically the same thing. This closing lesson is a checklist worth returning to as your projects grow.
Follow PEP 8
PEP 8 is Python's official style guide: 4 spaces per indentation level, snake_case for variables and functions, PascalCase for classes, a blank line or two between top-level definitions, lines kept under roughly 79-99 characters depending on team convention.
# Avoid
def CalculateTotal(itemList):
total=0
for i in itemList:total+=i
return total
# Prefer
def calculate_total(items):
total = 0
for item in items:
total += item
return totalYou don't need to memorize the whole spec — tools like black (an automatic formatter) and ruff or flake8 (linters that flag style and correctness issues) enforce most of it for you on save or in CI.
Use meaningful names
# Avoid
d = 10
def f(x, y):
return x * y * 0.08
# Prefer
DAYS_IN_TRIAL = 10
def calculate_tax(price, quantity):
return price * quantity * 0.08A name should tell the next reader what a value represents without needing a comment to explain it. This matters more than it seems — most time spent on real codebases is reading existing code, not writing new code.
Prefer EAFP over excessive checking
Python culture favors "Easier to Ask Forgiveness than Permission" — attempt the operation and handle the exception, rather than checking every precondition first:
# Avoid -- LBYL (Look Before You Leap), and still has a race condition
if "key" in my_dict:
value = my_dict["key"]
else:
value = default
# Prefer -- EAFP
try:
value = my_dict["key"]
except KeyError:
value = defaultFor this particular case, my_dict.get("key", default) is even more direct than either — but the EAFP principle shows up constantly beyond simple dict lookups, wherever checking-then-acting could be replaced by acting and catching the failure.
Write docstrings for anything non-obvious
A function whose name and parameters don't fully explain its behavior deserves a docstring (see the functions lesson earlier in this course) — especially anything with non-obvious edge cases, units, or side effects.
Don't repeat yourself
If the same logic appears in three places, it belongs in one function instead. Beyond less typing, it means a bug fix or behavior change happens in exactly one place rather than needing to be found and applied everywhere it was copied.
Keep functions and classes focused
A function that validates input, hits a database, formats a response, and logs the result is doing four jobs. Splitting it into four smaller, well-named functions makes each one independently testable and reusable — and far easier to reason about six months later.
A final checklist
- [ ] Code is formatted consistently (ideally via
blackor a similar auto-formatter). - [ ] A linter (
ruff,flake8, or similar) runs clean. - [ ] Names describe what a value or function actually is or does.
- [ ] Dependencies are pinned in
requirements.txt, installed inside a virtual environment. - [ ] Exceptions are caught narrowly, never with a bare
except:. - [ ] Public functions and classes have docstrings.
- [ ] No function or class is trying to do more than one clearly-named job.
None of this is exotic — it's the same language covered throughout this course, applied with a bit more discipline. That discipline is most of what separates Python that merely runs from Python a team can build on for years.
Test what you just learned
4 quick questions. Get all of them right to unlock the next lesson.
You can take the quiz without an account — logging in just lets your result count toward your progress.