
Créer et organiser des packages
Apprenez à créer des packages Python (des collections de modules). Structurez vos projets en répertoires, utilisez '__init__.py', et maîtrisez les importations relatives et absolues.
Qu'est-ce qu'un package en Python ? Une collection de modules
Un package en Python est un moyen d'organiser des modules en une hiérarchie de répertoires. Il permet de structurer des projets plus importants en regroupant les modules liés entre eux.
Un package est simplement un répertoire qui contient :
- Un fichier spécial nommé `__init__.py` (qui peut être vide). Ce fichier indique à Python que le répertoire doit être traité comme un package.
- Un ou plusieurs fichiers Python (modules).
- Eventuellement, d'autres sous-répertoires (sous-packages).
Les packages permettent d'éviter les collisions de noms entre modules, et de mieux organiser le code en le regroupant par fonctionnalité ou par domaine.
Créer un package : structure de répertoires et __init__.py
Pour créer un package, suivez ces étapes :
- Créez un répertoire pour votre package (le nom du répertoire sera le nom du package).
- Dans ce répertoire, créez un fichier vide nommé `__init__.py`.
- Ajoutez vos modules (fichiers `.py`) dans ce répertoire.
- Vous pouvez créer des sous-packages en créant des sous-répertoires, chacun contenant son propre fichier `__init__.py`.
Exemple :
Imaginons que vous voulez créer un package nommé `mon_package` pour gérer des opérations géométriques. Vous pourriez avoir la structure suivante :
mon_package/
__init__.py
formes.py # Module pour les formes géométriques (cercle, rectangle, etc.)
calculs.py # Module pour les calculs géométriques (aire, périmètre, etc.)
transformations.py #Module pour les transformations (rotation, translation...)Le fichier `__init__.py` peut être vide, mais il peut aussi contenir du code d'initialisation pour le package (par exemple, importer des fonctions ou des classes spécifiques des modules du package pour les rendre directement accessibles depuis le package). Il peut aussi spécifier une liste `__all__` qui liste les modules à importer si l'on fait `from mon_package import *`.
Importer des modules à partir d'un package
Pour importer des modules à partir d'un package, vous utilisez la notation pointée, en séparant les noms des packages, sous-packages et modules par des points.
En reprenant l'exemple précédent (`mon_package`), voici comment importer et utiliser les modules :
# Importer le module formes
import mon_package.formes
# Utiliser une fonction du module formes
# mon_package.formes.aire_cercle(5)
# Importer le module calculs avec un alias
import mon_package.calculs as calculs
# Utiliser une fonction du module calculs
# calculs.perimetre_rectangle(2, 3)
# Importer une fonction spécifique du module transformations
from mon_package.transformations import rotation
# Utiliser la fonction rotation
# rotation(point, angle)Vous pouvez également utiliser des importations relatives (voir section suivante).
Importations relatives et absolues
A l'intérieur d'un package, vous pouvez utiliser des importations relatives pour importer d'autres modules du même package, ou des sous-packages.
- Importation absolue : Spécifie le chemin complet du module à importer, à partir de la racine du projet (ou des répertoires d'installation de Python).
- Importation relative : Spécifie le chemin du module à importer par rapport au module courant, en utilisant la notation `.` (pour le répertoire courant) et `..` (pour le répertoire parent).
Exemple (en supposant que nous sommes dans le fichier `mon_package/calculs.py`) :
# Importation absolue du module formes (du même package)
import mon_package.formes
# Importation relative du module formes (du même package)
from . import formes # Le . signifie "le package courant" (mon_package)
# Si transformations.py était dans un sous-package 'geo' :
# from .geo import transformations # Le . signifie "le package courant" (mon_package)Dans le fichier `mon_package/formes.py`, vous pourriez importer une fonction du module `calculs` comme ceci :
# Dans mon_package/formes.py
from .calculs import distance # Importation relativeLes importations relatives sont généralement recommandées à l'intérieur d'un package, car elles rendent le code plus portable et facilitent la refactorisation. Cependant, elles peuvent être moins claires si la structure du package est complexe.
Depuis Python 3, les importations relatives implicites (sans le point initial) ne sont plus autorisées. Vous *devez* utiliser un point pour indiquer une importation relative.
Le rôle de __init__.py
Le fichier `__init__.py` joue plusieurs rôles importants dans un package :
- Indique à Python que le répertoire est un package : La présence de ce fichier (même vide) est nécessaire pour que Python reconnaisse le répertoire comme un package.
- Initialisation du package (facultatif) : Vous pouvez placer du code d'initialisation dans `__init__.py`. Ce code sera exécuté lorsque le package (ou un de ses sous-modules) est importé.
- Contrôler l'importation avec `*` (facultatif) : Vous pouvez définir une liste nommée `__all__` dans `__init__.py` pour spécifier quels modules doivent être importés lorsque vous utilisez `from mon_package import *`.
- Rendre des fonctions/classes directement accessibles depuis le package (facultatif) : Vous pouvez importer des fonctions ou des classes spécifiques de vos modules dans `__init__.py` pour les rendre accessibles directement depuis le package, sans avoir à spécifier le nom du module.
Exemple de `__init__.py` (avec initialisation et `__all__`) :
# mon_package/__init__.py
"""Ce package fournit des outils pour la géométrie."""
# Importer des fonctions/classes spécifiques pour les rendre accessibles
# directement depuis le package
from .formes import Cercle, Rectangle
from .calculs import aire_cercle
# Définir __all__ pour contrôler l'importation avec *
__all__ = ["Cercle", "Rectangle", "aire_cercle"]
# Code d'initialisation (facultatif)
print("Initialisation du package mon_package")Avec ce `__init__.py`, vous pourriez faire :
import mon_package
# Accès direct à Cercle, Rectangle et aire_cercle
cercle = mon_package.Cercle(5)
aire = mon_package.aire_cercle(5)
# Ou avec from ... import
from mon_package import Cercle, aire_cercleSans l'importation dans `__init__.py`, il faudrait faire `from mon_package.formes import Cercle`.