Beyond the Basics: A Professional Guide to Documenting Python Code
Overview
Code is read far more often than it is written. While developers spend hours crafting logic, the lifespan of that code depends on how easily others—and your future self—can understand it. This guide explores a multi-layered approach to documentation, moving from inline comments to automated documentation websites. By integrating these techniques, you ensure your software remains accessible, maintainable, and professional.
Prerequisites
To follow this guide, you should have a basic understanding of
Key Libraries & Tools
- Better Comments: A VS Code extension that categorizes comments by color (alerts, TODOs, highlights).
- Auto Docstring: Generates template docstrings in various formats like NumPy or Google style.
- MkDocs: A static site generator geared towards building project documentation.
- mkdocstrings: AnMkDocsplugin that automatically extracts docstrings from Python source code.
Code Walkthrough
1. Intentional Commenting
Stop repeating your code in comments. If a line says history.append(data), a comment saying "Appends data to history" is noise. Instead, explain the why.

# Log the deposit to maintain a permanent audit trail
self.transaction_history.append(("deposit", datetime.now(), amount))
2. Strict Type Hinting
Type hints act as living documentation. By using the strict mode in your type checker, you force the code to explicitly state what data it expects and returns.
from typing import Self
class BankAccount:
def __init__(self, initial_balance: int) -> None:
self.balance = initial_balance
def transfer(self, target: Self, amount: int) -> None:
self.withdraw(amount)
target.deposit(amount)
3. Structured Docstrings
Use structured formats like
def withdraw(self, amount: int) -> None:
"""
Withdraws a specific amount from the account.
Parameters
----------
amount : int
The total value to remove from the balance.
Raises
------
InsufficientBalanceError
If the account balance is lower than the amount.
"""
Syntax Notes
The Self type, introduced in recent Python versions, allows a class method to refer to an instance of its own class without hardcoding the class name. This makes refactoring easier and types more accurate. Additionally, using from __future__ import annotations can resolve circular references where a class needs to reference itself before it is fully defined.
Practical Examples
These techniques are essential when building open-source libraries or working in large engineering teams. When a new developer joins a project, they can run mkdocs serve to see a local version of the API documentation, complete with type requirements and usage examples extracted directly from the source code.
Tips & Gotchas
Documentation can easily become a burden if it grows faster than the logic. A common pitfall is writing docstrings that are longer than the function's code. If you find yourself writing paragraphs to explain a single function, the problem likely isn't the documentation—it's the complexity of the code. Focus on clean naming and logical structure first; good documentation should only be the finishing touch.