Architecture et Structure de Projets Python
Concevez des projets Python bien organisés avec des limites de modules clairs, des interfaces publiques explicites et des structures de répertoires maintenables. Une bonne organisation rend le code découvrable et les modifications prévisibles.
Quand utiliser cette compétence
- Démarrer un nouveau projet Python à partir de zéro
- Réorganiser une base de code existante pour plus de clarté
- Définir les API publiques de modules avec
__all__ - Choisir entre des structures de répertoires plates et imbriquées
- Déterminer les stratégies de placement des fichiers de test
- Créer des packages de bibliothèque réutilisables
Concepts fondamentaux
1. Cohésion des modules
Regroupez le code connexe qui change ensemble. Un module doit avoir un objectif unique et clair.
2. Interfaces explicites
Définissez ce qui est public avec __all__. Tout ce qui n'est pas listé est un détail d'implémentation interne.
3. Hiérarchies plates
Privilégiez les structures de répertoires peu profondes. Ajoutez de la profondeur uniquement pour les véritables sous-domaines.
4. Conventions cohérentes
Appliquez les modèles de dénomination et d'organisation uniformément dans le projet.
Démarrage rapide
myproject/
├── src/
│ └── myproject/
│ ├── __init__.py
│ ├── services/
│ ├── models/
│ └── api/
├── tests/
├── pyproject.toml
└── README.md
Modèles fondamentaux
Modèle 1 : Un concept par fichier
Chaque fichier doit se concentrer sur un seul concept ou un ensemble étroitement lié de fonctions. Envisagez une division quand un fichier :
- Gère plusieurs responsabilités sans rapport
- Dépasse 300-500 lignes (varie selon la complexité)
- Contient des classes qui changent pour différentes raisons
# Bon : Fichiers focalisés
# user_service.py - Logique métier utilisateur
# user_repository.py - Accès aux données utilisateur
# user_models.py - Structures de données utilisateur
# À éviter : Fichiers fourre-tout
# user.py - Contient service, repository, modèles, utilitaires...
Modèle 2 : API publiques explicites avec __all__
Définissez l'interface publique pour chaque module. Les membres non listés sont des détails d'implémentation interne.
# mypackage/services/__init__.py
from .user_service import UserService
from .order_service import OrderService
from .exceptions import ServiceError, ValidationError
__all__ = [
"UserService",
"OrderService",
"ServiceError",
"ValidationError",
]
# Les aides internes restent privées par omission
# from .internal_helpers import _validate_input # Non exporté
Modèle 3 : Structure de répertoires plate
Privilégiez l'imbrication minimale. Les hiérarchies profondes rendent les imports verbeux et la navigation difficile.
# Préféré : Structure plate
project/
├── api/
│ ├── routes.py
│ └── middleware.py
├── services/
│ ├── user_service.py
│ └── order_service.py
├── models/
│ ├── user.py
│ └── order.py
└── utils/
└── validation.py
# À éviter : Imbrication profonde
project/core/internal/services/impl/user/
Ajoutez des sous-packages uniquement s'il y a un véitable sous-domaine nécessitant une isolation.
Modèle 4 : Organisation des fichiers de test
Choisissez une approche et appliquez-la de manière cohérente dans tout le projet.
Option A : Tests colocalisés
src/
├── user_service.py
├── test_user_service.py
├── order_service.py
└── test_order_service.py
Avantages : Les tests vivent à côté du code qu'ils vérifient. Facile de voir les lacunes de couverture.
Option B : Répertoire de test parallèle
src/
├── services/
│ ├── user_service.py
│ └── order_service.py
tests/
├── services/
│ ├── test_user_service.py
│ └── test_order_service.py
Avantages : Séparation nette entre le code de production et le code de test. Standard pour les projets plus grands.
Modèles avancés
Modèle 5 : Initialisation de package
Utilisez __init__.py pour fournir une interface publique propre aux consommateurs du package.
# mypackage/__init__.py
"""MyPackage - A library for doing useful things."""
from .core import MainClass, HelperClass
from .exceptions import PackageError, ConfigError
from .config import Settings
__all__ = [
"MainClass",
"HelperClass",
"PackageError",
"ConfigError",
"Settings",
]
__version__ = "1.0.0"
Les consommateurs peuvent alors importer directement depuis le package :
from mypackage import MainClass, Settings
Modèle 6 : Architecture en couches
Organisez le code par couche architecturale pour une séparation nette des préoccupations.
myapp/
├── api/ # Gestionnaires HTTP, requête/réponse
│ ├── routes/
│ └── middleware/
├── services/ # Logique métier
├── repositories/ # Accès aux données
├── models/ # Entités du domaine
├── schemas/ # Schémas API (Pydantic)
└── config/ # Configuration
Chaque couche ne doit dépendre que des couches en dessous, jamais des couches au-dessus.
Modèle 7 : Structure orientée domaine
Pour les applications complexes, organisez par domaine métier plutôt que par couche technique.
ecommerce/
├── users/
│ ├── models.py
│ ├── services.py
│ ├── repository.py
│ └── api.py
├── orders/
│ ├── models.py
│ ├── services.py
│ ├── repository.py
│ └── api.py
└── shared/
├── database.py
└── exceptions.py
Dénomination des fichiers et modules
Conventions
- Utilisez
snake_casepour tous les noms de fichiers et modules :user_repository.py - Évitez les abréviations qui obscurcissent le sens :
user_repository.pyau lieu deusr_repo.py - Associez les noms de classes aux noms de fichiers :
UserServicedansuser_service.py
Style d'import
Utilisez les imports absolus pour la clarté et la fiabilité :
# Préféré : Imports absolus
from myproject.services import UserService
from myproject.models import User
# À éviter : Imports relatifs
from ..services import UserService
from . import models
Les imports relatifs peuvent se casser quand les modules sont déplacés ou réorganisés.
Résumé des bonnes pratiques
- Gardez les fichiers focalisés - Un concept par fichier, envisagez une division à 300-500 lignes (varie selon la complexité)
- Définissez
__all__explicitement - Rendez les interfaces publiques claires - Privilégiez les structures plates - Ajoutez de la profondeur uniquement pour les véritables sous-domaines
- Utilisez les imports absolus - Plus fiables et plus clairs
- Soyez cohérent - Appliquez les modèles uniformément dans le projet
- Associez les noms au contenu - Les noms de fichiers doivent décrire leur objectif
- Séparez les préoccupations - Gardez les couches distinctes et les dépendances circulant dans une direction
- Documentez votre structure - Incluez un README expliquant l'organisation