Документирование кода Python
Зачем документировать
Код пишется один раз, но читается многократно. Хорошая документация помогает новым разработчикам, служит контрактом для API и помогает вам через 6 месяцев.
Docstrings
Docstring — строковый литерал, стоящий первой инструкцией в модуле, классе или функции:
def calculate_bmi(weight_kg: float, height_m: float) -> float:
"""Calculate Body Mass Index (BMI).
Args:
weight_kg: Weight in kilograms. Must be positive.
height_m: Height in meters. Must be positive.
Returns:
BMI value as float.
Raises:
ValueError: If weight or height is non-positive.
Examples:
>>> calculate_bmi(70, 1.75)
22.857142857142858
"""
if weight_kg <= 0 or height_m <= 0:
raise ValueError("Weight and height must be positive")
return weight_kg / (height_m ** 2)
# Access docstring
print(calculate_bmi.__doc__)
help(calculate_bmi)
Однострочные docstrings
def square(n: int) -> int:
"""Return the square of n."""
return n * n
Стили документирования
Google Style (рекомендуемый)
class UserService:
"""Service for managing user accounts.
Attributes:
repository: User data repository.
notifier: Notification service.
"""
def create_user(self, name: str, email: str, role: str = "user") -> "User":
"""Create a new user account.
Args:
name: Full name, 1-100 characters.
email: Email address. Must be unique.
role: User role. Defaults to "user".
Returns:
Newly created User object with assigned ID.
Raises:
ValueError: If name is empty or email invalid.
DuplicateError: If email already exists.
"""
...
NumPy/SciPy Style
def normalize(data: list[float], method: str = "minmax") -> list[float]:
"""Normalize a list of numerical values.
Parameters
----------
data : list[float]
Input data. Must contain at least 2 values.
method : str, optional
Normalization method. Default is "minmax".
Returns
-------
list[float]
Normalized values.
Examples
--------
>>> normalize([1, 2, 3, 4, 5])
[0.0, 0.25, 0.5, 0.75, 1.0]
"""
...
Комментарии vs Docstrings
# Comments explain WHY (implementation details)
# Docstrings explain WHAT (public API contract)
class Cache:
"""In-memory LRU cache with TTL support."""
def get(self, key: str) -> str | None:
"""Get value by key, or None if expired/missing."""
# Check expiration first to avoid returning stale data
if self._is_expired(key):
del self._store[key]
return None
return self._store.get(key)
Когда НЕ нужны комментарии
# BAD: comment repeats the code
i += 1 # Increment i by 1
# GOOD: explains non-obvious decision
# Use binary search because the list is sorted and can have 1M+ elements
index = bisect.bisect_left(sorted_items, target)
# GOOD: explains business rule
# Free shipping for orders over 5000 (marketing decision Q1 2026)
if order.total >= 5000:
order.shipping_cost = 0
Инструменты генерации документации
pydoc — встроенный
python -m pydoc json # View in terminal
python -m pydoc myapp.utils
python -m pydoc -b # Start local docs server
mkdocs + mkdocstrings
pip install mkdocs mkdocs-material mkdocstrings[python]
# mkdocs.yml
site_name: MyApp Documentation
theme:
name: material
plugins:
- search
- mkdocstrings:
handlers:
python:
options:
docstring_style: google
<!-- docs/api/services.md -->
# Services API
::: myapp.services.UserService
mkdocs serve # Dev server
mkdocs build # Build static site
Type Hints как документация
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
class OrderStatus(Enum):
PENDING = "pending"
CONFIRMED = "confirmed"
SHIPPED = "shipped"
DELIVERED = "delivered"
@dataclass
class Order:
"""Customer order.
Attributes:
id: Unique order identifier.
customer_email: Customer's email.
items: List of product names.
total: Total price in rubles.
status: Current order status.
"""
id: int
customer_email: str
items: list[str]
total: float
status: OrderStatus = OrderStatus.PENDING
created_at: datetime | None = None
Чеклист документирования
| Что | Документировать? |
|---|---|
| Публичные функции/классы | Всегда (docstring) |
| Публичные модули | Всегда |
| Приватные методы | По необходимости |
| Нетривиальная логика | Комментарий |
| Бизнес-правила | Обязательно |
| Workaround/hack | Обязательно + ссылка на issue |
| Очевидный код | Не нужно |