Style et Documentation du Code Python
Un style de code cohérent et une documentation claire rendent les bases de code maintenables et collaboratives. Cette compétence couvre les outils Python modernes, les conventions de nommage et les normes de documentation.
Quand Utiliser Cette Compétence
- Configurer le linting et le formatting pour un nouveau projet
- Écrire ou examiner des docstrings
- Établir des normes de codage d'équipe
- Configurer ruff, mypy ou pyright
- Examiner le code pour la cohérence du style
- Créer la documentation du projet
Concepts Fondamentaux
1. Formatting Automatisé
Laissez les outils gérer les débats de formatage. Configurez une fois, appliquez automatiquement.
2. Nommage Cohérent
Suivez les conventions PEP 8 avec des noms significatifs et descriptifs.
3. Documentation Comme Code
Les docstrings doivent être maintenues aux côtés du code qu'elles décrivent.
4. Annotations de Type
Le code Python moderne devrait inclure des type hints pour tous les API publiques.
Démarrage Rapide
# Installer les outils modernes
pip install ruff mypy
# Configurer dans pyproject.toml
[tool.ruff]
line-length = 120
target-version = "py312" # Ajustez selon la version Python minimale de votre projet
[tool.mypy]
strict = true
Patterns Fondamentaux
Pattern 1 : Outils Python Modernes
Utilisez ruff comme linter et formateur tout-en-un. Il remplace flake8, isort et black par un seul outil rapide.
# pyproject.toml
[tool.ruff]
line-length = 120
target-version = "py312" # Ajustez selon la version Python minimale de votre projet
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
"SIM", # flake8-simplify
]
ignore = ["E501"] # Line length handled by formatter
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
Exécutez avec :
ruff check --fix . # Linter et corriger automatiquement
ruff format . # Formater le code
Pattern 2 : Configuration du Type Checking
Configurez la vérification de type stricte pour le code de production.
# pyproject.toml
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_ignores = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
Alternative : Utilisez pyright pour une vérification plus rapide.
[tool.pyright]
pythonVersion = "3.12"
typeCheckingMode = "strict"
Pattern 3 : Conventions de Nommage
Suivez PEP 8 en mettant l'accent sur la clarté plutôt que la concision.
Fichiers et Modules :
# Bon : snake_case descriptif
user_repository.py
order_processing.py
http_client.py
# À éviter : Abréviations
usr_repo.py
ord_proc.py
http_cli.py
Classes et Fonctions :
# Classes : PascalCase
class UserRepository:
pass
class HTTPClientFactory: # Les acronymes restent en majuscules
pass
# Fonctions et variables : snake_case
def get_user_by_email(email: str) -> User | None:
retry_count = 3
max_connections = 100
Constantes :
# Constantes au niveau du module : SCREAMING_SNAKE_CASE
MAX_RETRY_ATTEMPTS = 3
DEFAULT_TIMEOUT_SECONDS = 30
API_BASE_URL = "https://api.example.com"
Pattern 4 : Organisation des Imports
Groupez les imports dans un ordre cohérent : bibliothèque standard, tiers, local.
# Bibliothèque standard
import os
from collections.abc import Callable
from typing import Any
# Packages tiers
import httpx
from pydantic import BaseModel
from sqlalchemy import Column
# Imports locaux
from myproject.models import User
from myproject.services import UserService
Utilisez exclusivement les imports absolus :
# Préféré
from myproject.utils import retry_decorator
# À éviter : imports relatifs
from ..utils import retry_decorator
Patterns Avancés
Pattern 5 : Docstrings Style Google
Écrivez des docstrings pour tous les classes, méthodes et fonctions publiques.
Fonction Simple :
def get_user(user_id: str) -> User:
"""Récupérer un utilisateur par son identifiant unique."""
...
Fonction Complexe :
def process_batch(
items: list[Item],
max_workers: int = 4,
on_progress: Callable[[int, int], None] | None = None,
) -> BatchResult:
"""Traiter les éléments de manière concurrente avec un pool de workers.
Traite chaque élément du batch en utilisant le nombre configuré de
workers. La progression peut être suivie via le callback optionnel.
Args:
items: Les éléments à traiter. Ne doit pas être vide.
max_workers: Nombre maximum de workers concurrents. Par défaut 4.
on_progress: Callback optionnel recevant les comptes (complétés, total).
Returns:
BatchResult contenant les éléments réussis et les échecs avec
leurs exceptions associées.
Raises:
ValueError: Si items est vide.
ProcessingError: Si le batch ne peut pas être traité.
Example:
>>> result = process_batch(items, max_workers=8)
>>> print(f"Processed {len(result.succeeded)} items")
"""
...
Docstring de Classe :
class UserService:
"""Service pour gérer les opérations utilisateur.
Fournit des méthodes pour créer, récupérer, mettre à jour et
supprimer des utilisateurs avec validation et gestion d'erreurs appropriées.
Attributes:
repository: La couche d'accès aux données pour la persistance des utilisateurs.
logger: Instance de logger pour le suivi des opérations.
Example:
>>> service = UserService(repository, logger)
>>> user = service.create_user(CreateUserInput(...))
"""
def __init__(self, repository: UserRepository, logger: Logger) -> None:
"""Initialiser le service utilisateur.
Args:
repository: Couche d'accès aux données pour les utilisateurs.
logger: Logger pour le suivi des opérations.
"""
self.repository = repository
self.logger = logger
Pattern 6 : Longueur de Ligne et Formatting
Définissez la longueur de ligne à 120 caractères pour les affichages modernes tout en maintenant la lisibilité.
# Bon : Sauts de ligne lisibles
def create_user(
email: str,
name: str,
role: UserRole = UserRole.MEMBER,
notify: bool = True,
) -> User:
...
# Bon : Chaîner les appels de méthode clairement
result = (
db.query(User)
.filter(User.active == True)
.order_by(User.created_at.desc())
.limit(10)
.all()
)
# Bon : Formater les longues chaînes
error_message = (
f"Failed to process user {user_id}: "
f"received status {response.status_code} "
f"with body {response.text[:100]}"
)
Pattern 7 : Documentation du Projet
Structure README :
# Project Name
Brève description de ce que fait le projet.
## Installation
\`\`\`bash
pip install myproject
\`\`\`
## Démarrage Rapide
\`\`\`python
from myproject import Client
client = Client(api_key="...")
result = client.process(data)
\`\`\`
## Configuration
Documentez les variables d'environnement et les options de configuration.
## Développement
\`\`\`bash
pip install -e ".[dev]"
pytest
\`\`\`
Format CHANGELOG (Keep a Changelog) :
# Changelog
## [Unreleased]
### Added
- New feature X
### Changed
- Modified behavior of Y
### Fixed
- Bug in Z
Résumé des Bonnes Pratiques
- Utiliser ruff - Outil unique pour le linting et le formatting
- Activer mypy strict - Détecter les erreurs de type avant l'exécution
- Lignes de 120 caractères - Standard moderne pour la lisibilité
- Noms descriptifs - Clarté plutôt que concision
- Imports absolus - Plus maintenables que les imports relatifs
- Docstrings style Google - Documentation cohérente et lisible
- Documenter les API publiques - Chaque fonction publique a besoin d'une docstring
- Garder la documentation à jour - Traiter la documentation comme du code
- Automatiser en CI - Exécuter les linters à chaque commit
- Cibler Python 3.10+ - Pour les nouveaux projets, Python 3.12+ est recommandé pour les fonctionnalités modernes du langage