
Le fichier __init__.py
Comprenez le rôle essentiel du fichier '__init__.py' dans les packages Python. Découvrez comment il transforme un répertoire en package, comment l'utiliser pour l'initialisation, et comment contrôler l'importation des modules.
Rôle principal : marquer un répertoire comme un package
La présence d'un fichier nommé `__init__.py` (avec deux traits de soulignement avant et après) dans un répertoire indique à Python que ce répertoire doit être traité comme un package. Sans ce fichier, Python considère le répertoire comme un simple répertoire, et vous ne pourrez pas importer les modules qu'il contient comme faisant partie d'un package.
Le fichier `__init__.py` peut être vide. Sa simple présence suffit à transformer le répertoire en package.
Exemple :
Si vous avez la structure suivante :
mon_package/
__init__.py
module1.py
module2.py`mon_package` est un package Python grâce à la présence de `__init__.py`. Vous pouvez alors faire `import mon_package.module1` ou `from mon_package import module2`.
Si vous supprimez `__init__.py`, ces importations ne fonctionneront plus (Python lèvera une `ModuleNotFoundError`).
Initialisation du package : code exécuté à l'importation
Le fichier `__init__.py` peut contenir du code Python. Ce code est exécuté lorsque le package (ou un de ses sous-modules) est importé pour la première fois.
Cela permet d'effectuer des tâches d'initialisation, comme :
- Définir des variables globales au niveau du package.
- Importer des fonctions, classes, ou variables de sous-modules pour les rendre directement accessibles depuis le package.
- Configurer des options de logging.
- Ouvrir des connexions à des bases de données (déconseillé en général, préférez le faire à la demande).
- Effectuer d'autres opérations nécessaires à l'initialisation du package.
Exemple :
Si `mon_package/__init__.py` contient :
# mon_package/__init__.py
print("Initialisation du package mon_package")
VERSION = "1.0"Alors, lorsque vous faites `import mon_package` (ou `import mon_package.module1`, etc.), le message "Initialisation du package mon_package" sera affiché, et la variable `mon_package.VERSION` sera définie.
Le code dans `__init__.py` n'est exécuté qu'une seule fois, lors de la *première* importation du package (ou d'un de ses sous-modules) dans une session Python.
Contrôler l'importation avec * : la variable __all__
Lorsque vous utilisez l'instruction `from mon_package import *`, Python importe par défaut tous les noms (fonctions, classes, variables) définis dans le module `mon_package` qui ne commencent pas par un trait de soulignement.
Cependant, si le fichier `__init__.py` du package définit une liste nommée `__all__`, alors seuls les noms listés dans `__all__` seront importés avec `from mon_package import *`.
Cela permet de contrôler explicitement ce qui est exposé par le package lorsque `*` est utilisé, et d'éviter d'importer des noms qui ne sont pas destinés à être utilisés à l'extérieur du package.
Exemple :
Si `mon_package/__init__.py` contient :
# mon_package/__init__.py
__all__ = ["fonction1", "ClasseA"]
def fonction1():
pass
def fonction2(): # Ne sera pas importée avec from mon_package import *
pass
class ClasseA:
pass
class _ClassePrivee: # Ne sera pas importée avec from mon_package import *
passAlors, `from mon_package import *` importera uniquement `fonction1` et `ClasseA`, mais pas `fonction2` ni `_ClassePrivee`.
Si `__all__` n'est pas défini, `from mon_package import *` importera tous les noms qui ne commencent pas par un trait de soulignement.
Il est généralement déconseillé d'utiliser `from package import *`, même avec `__all__`. Il est préférable d'importer explicitement les noms dont vous avez besoin.
Simplifier l'accès aux éléments du package
Une utilisation courante de `__init__.py` est de simplifier l'accès aux fonctions, classes, ou variables définies dans les sous-modules du package.
Au lieu de forcer l'utilisateur du package à importer chaque sous-module individuellement, vous pouvez importer les éléments importants dans `__init__.py`, les rendant ainsi accessibles directement depuis le package.
Exemple :
Structure :
mon_package/
__init__.py
module1.py # Contient une fonction 'fonction_utile'
module2.py`mon_package/module1.py` :
# mon_package/module1.py
def fonction_utile():
print("Fonction utile appelée")Sans modification de `__init__.py`, l'utilisateur devrait faire :
from mon_package.module1 import fonction_utile
fonction_utile()Avec la modification suivante de `__init__.py` :
# mon_package/__init__.py
from .module1 import fonction_utile # Importation relativeL'utilisateur peut maintenant faire :
from mon_package import fonction_utile
fonction_utile()Ou même :
import mon_package
mon_package.fonction_utile()Cela rend l'utilisation du package plus pratique, car l'utilisateur n'a pas besoin de connaître la structure interne du package (où se trouve exactement `fonction_utile`).
__init__.py vide vs. __init__.py avec du code
Le fichier `__init__.py` peut être vide, ou il peut contenir du code. Voici un résumé des différences :
- `__init__.py` vide : Indique simplement que le répertoire est un package. Aucune initialisation particulière n'est effectuée.
- `__init__.py` avec du code : Permet d'effectuer des tâches d'initialisation, de contrôler l'importation avec `*`, et de simplifier l'accès aux éléments du package.
Le choix entre un `__init__.py` vide et un `__init__.py` avec du code dépend de vos besoins. Si vous voulez juste que le répertoire soit reconnu comme un package, un `__init__.py` vide suffit. Si vous voulez effectuer des tâches d'initialisation ou simplifier l'utilisation du package, vous pouvez ajouter du code à `__init__.py`.
Dans les projets modernes, il est courant de trouver des `__init__.py` qui ne sont pas vides, mais qui contiennent du code pour améliorer l'expérience utilisateur du package.