Python Coding Standards
A comprehensive style and quality guide based on PEP 8 and common community
conventions
1. Purpose and Scope
This document establishes a consistent set of conventions for writing Python code across a team or
organization. Consistent style reduces the cognitive overhead of reading unfamiliar code, makes code
review faster and more focused on substance rather than formatting, and lowers the likelihood of
certain classes of bugs. These guidelines are grounded in PEP 8, the official Python style guide, along
with widely adopted community and tooling conventions (Black, flake8, mypy) that have become de
facto standards in most modern Python codebases.
2. Naming Conventions
Element Convention
Variables / functions snake_case (e.g., user_count, get_data())
Classes PascalCase (e.g., UserAccount)
Constants UPPER_SNAKE_CASE (e.g., MAX_RETRIES)
Modules / packages short, lowercase, no underscores if possible
Private members leading underscore, e.g., _internal_value
'Very private' / name-mangled double leading underscore, e.g., __secret
Type variables (generics) single uppercase letter or PascalCase, e.g., T, KeyType
2.1 Why naming matters
Names are the primary documentation most readers will ever see. A well-chosen name eliminates the
need for a comment explaining what a variable holds. Avoid abbreviations that aren't broadly
understood, avoid single-letter names outside of small loop counters or well-established math contexts,
and never reuse a name for two conceptually different things within the same scope.
3. Formatting
• Indent with 4 spaces, never tabs; mixing the two is a common source of subtle bugs.
• Limit lines to 79–99 characters (PEP 8 recommends 79; many teams standardize on 88–99 when
using Black).
• Two blank lines between top-level functions/classes; one blank line between methods inside a
class.
• Use spaces around operators and after commas: a = b + c, not a=b+c.
• Avoid trailing whitespace at the end of lines and files; most editors can be configured to strip it
automatically.
• Wrap long function calls and definitions using parentheses with one argument per line when
needed for readability.
4. Imports
import os
import sys
import requests
import numpy as np
from mypackage import module
from [Link] import helper_function
4.1 Import rules
• Group imports: standard library, then third-party, then local — separated by a blank line.
• One import per line; avoid wildcard imports (from module import *) since they hide where names
come from.
• Use absolute imports over relative imports where practical, for clarity when files move.
• Sort imports alphabetically within each group; tools like isort automate this.
• Avoid circular imports by structuring modules so dependencies flow in one direction.
5. Documentation and Comments
• Every public module, class, and function should have a docstring using triple quotes.
• Follow a consistent docstring style (Google, NumPy, or reST format) across the entire codebase.
• Type hints are strongly recommended for function signatures; they double as documentation and
enable static checking.
• Comments should explain *why*, not *what* — the code itself should make the 'what' clear.
• Keep comments up to date; a stale comment is worse than no comment at all.
5.1 Example docstring and type hints
def add(a: int, b: int) -> int:
"""Return the sum of two integers.
Args:
a: First addend.
b: Second addend.
Returns:
The sum of a and b.
"""
return a + b
6. Error Handling
• Catch specific exceptions rather than a bare except: clause, which can hide bugs.
• Use custom exception classes to represent domain-specific error conditions.
• Avoid using exceptions for normal control flow; reserve them for truly exceptional situations.
• Always clean up resources with try/finally or, preferably, context managers (with statements).
• Log exceptions with enough context (stack trace, relevant variable values) to debug after the fact.
6.1 Example
try:
result = risky_operation()
except ValueError as exc:
[Link]("Invalid input: %s", exc)
raise
finally:
cleanup_resources()
7. Testing Standards
• Use pytest as the standard test runner unless the project has an established alternative.
• Name test files test_.py and test functions test_.
• Aim for tests that are independent, repeatable, and fast; avoid tests that depend on execution
order.
• Use fixtures for shared setup rather than duplicating setup code across tests.
• Mock external services (databases, APIs) in unit tests; reserve real integrations for integration
tests.
• Target meaningful coverage of business logic rather than chasing a raw coverage percentage.
8. Project Structure
• Use a src/ layout or a clearly named top-level package directory to avoid import ambiguity.
• Keep a [Link] or [Link] with pinned or constrained dependency versions.
• Separate application code, tests, and scripts into distinct top-level directories.
• Include a README describing setup, running tests, and key architectural decisions.
9. Security Considerations
• Never hardcode secrets, API keys, or passwords in source code; use environment variables or a
secrets manager.
• Validate and sanitize all external input, especially before using it in file paths, shell commands, or
queries.
• Use parameterized queries (via an ORM or DB-API placeholders) to prevent SQL injection when
working with databases.
• Keep dependencies up to date and monitor for known vulnerabilities (e.g., via pip-audit or
Dependabot).
• Avoid using eval() or exec() on untrusted input.
10. Common Pitfalls
• Mutable default arguments (def f(x=[])) persist across calls and are a frequent source of bugs.
• Modifying a list while iterating over it can silently skip elements.
• Comparing floating point numbers with == instead of using a tolerance-based comparison.
• Shadowing built-in names (e.g., naming a variable list or dict) makes code confusing and
error-prone.
• Forgetting that Python integers and strings are immutable can lead to unexpected behavior with
in-place-looking operations.
11. Tooling and Automation
• Use Black (or an equivalent) as an opinionated auto-formatter so formatting is never debated in
code review.
• Use flake8 or ruff for linting to catch unused imports, undefined names, and style violations.
• Use mypy for static type checking if the codebase uses type hints extensively.
• Run all of the above automatically via pre-commit hooks and again in CI so nothing merges
unchecked.
12. Version Control and Code Review
• Write commit messages that explain the intent of a change, not just what files changed.
• Keep pull requests small and focused on a single logical change where possible.
• Every PR should include or update relevant tests before merging.
• Reviewers should check for correctness, readability, and adherence to these standards, not just
working code.
13. Summary Checklist
• Consistent snake_case / PascalCase naming throughout.
• Formatted with Black, linted with flake8/ruff, type-checked with mypy.
• Docstrings on all public functions, classes, and modules.
• Specific exception handling with proper cleanup.
• Tests written for new logic and running in CI.
• No secrets committed to source control.
Compiled as an original summary of widely-followed community and vendor style guidelines, for internal reference use.