Apprendre Python : Modules
Apprenez à structurer vos projets Python en utilisant des modules et packages pour organiser votre code de manière efficace.
Qu’est-ce qu’un module ?
En Python, les modules permettent de diviser un programme en parties plus petites et indépendantes qui peuvent être réutilisées dans d’autres parties du programme.
Un module est représenté par un fichier .py
qui peut contenir des variables, des fonctions, etc., qui peuvent être importées dans d’autres modules.
De ce fait, chaque module a son propre contexte. Il ne peut donc pas interférer avec d’autres modules ni polluer la portée globale.
Cela permet de structurer et d’organiser le code de manière plus claire et de prévenir les conflits de noms entre les différentes parties du programme.
3 grands types de modules
Dans un projet Python, on distingue trois grands types de modules : « Core Modules », « Local Modules » et « Third-Party Modules ».
1. Core Modules
Les Core Modules sont les modules fournis avec Python par défaut. Ils font partie intégrante de la bibliothèque standard de Python.
Bien que ces modules fassent partie intégrante du langage, ils doivent être importés avant de pouvoir être utilisés dans le code.
Le tableau suivant répertorie certains des Core Modules principaux de Python.
Module | Description |
---|---|
os | Fournit des fonctions pour interagir avec le système d’exploitation, comme la gestion des fichiers et des processus. |
sys | Fournit des fonctions et des variables liées à l’environnement d’exécution Python, comme la gestion des arguments de ligne de commande et l’interaction avec l’interpréteur Python. |
math | Offre des fonctions mathématiques standard, comme les fonctions trigonométriques et logarithmiques. |
datetime | Gère les dates et les heures, permet de manipuler et formater les objets de date/heure. |
json | Permet de lire, écrire et manipuler des données au format JSON (JavaScript Object Notation). |
re | Fournit des fonctions pour la manipulation d’expressions régulières, utile pour le traitement de texte et la recherche de motifs. |
2. Local Modules
Les modules locaux sont des modules créés localement (par vous) dans votre application Python.
Ces modules incluent différentes fonctionnalités de votre application dans des fichiers et dossiers distincts.
3. Third-Party Modules
Vous pouvez également décider de packager et de distribuer vos modules locaux, afin que la communauté Python puisse les utiliser : ils deviendront alors des third-party modules (modules tiers).
Nous détaillerons comment installer des modules tiers via le gestionnaire de paquets pip
au chapitre suivant.
Création d’un module
Créer un fichier 📄 module1.py
et placer le code suivant à l’intérieur :
def count_vowels(text):
vowels = "aeiouAEIOU"
count = 0
for char in text:
if char in vowels:
count += 1
return count
Cette fonction retourne le nombre de voyelles contenues dans une chaîne de caractères.
Importation et utilisation d’un module
Pour importer un module Python, on procède en utilisant le mot-clé import
, suivi d’un nom de variable, vouée à recevoir le contenu du module.
import module1
Import complet
L’import complet d’un module consiste par définition à importer l’ensemble de son contenu.
import module1
print(module1.count_vowels("laConsole"))
La variable module1
contient l’ensemble des éléments du module (variables, fonctions, etc.). Pour accéder à un élément, on doit donc utiliser la notation <nom_paquet>.<nom_element>
.
Import partiel
L’import partiel d’un module consiste à importer uniquement les éléments qui nous intéressent. Cela est rendu possible via l’usage du mot-clé from
.
def count_vowels(text):
vowels = "aeiouAEIOU"
count = 0
for char in text:
if char in vowels:
count += 1
return count
def count_consonants(text):
consonants = "bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ"
count = 0
for char in text:
if char in consonants:
count += 1
return count
from module1 import count_vowels
print(count_vowels("laConsole")) # ✅ Affiche 4
print(count_consonants("laConsole")) # ❌ Erreur => 'count_consonants' is not defined
L’élément importé étant individuellement spécifié, il n’est plus nécessaire de préfixer son usage du nom du module (ici module1
).
Pour importer plusieurs éléments, il suffit de les séparer par des virgules :
from module1 import count_vowels, count_consonants
print(count_vowels("laConsole")) # ✅ Affiche 4
print(count_consonants("laConsole")) # ✅ Affiche 5
Du module au package
Un package est simplement un dossier contenant un ensemble de modules organisés dans des sous-dossiers et éventuellement des fichiers supplémentaires, le tout étant destiné à être utilisé comme un ensemble cohérent.
Les packages permettent de structurer le code de manière plus organisée, surtout lorsqu’un projet devient complexe.
Créer un package
Créer un package est une tâche relativement simple :
- Créer un dossier pour le package : Le nom du dossier sera le nom du package.
- Ajouter un fichier
📄 __init__.py
: Ce fichier est requis pour que Python reconnaisse le dossier comme un package. Il peut rester vide ou contenir du code d’initialisation, des importations d’autres modules du package, ou des éléments de configuration (variables et fonctions partagées). - Ajouter des modules au package : Créez des fichiers portant l’extension
.py
dans le dossier du package pour ajouter des modules. Ces modules contiendront les fonctions, variables, etc., à inclure dans le package.
Voici un exemple de structure de package nommé math_utils
, dédié à la mise à disposition de fonctions mathématiques sur-mesure :
📂 math_utils/
├── 📄 __init__.py
├── 📄 format.py
└── 📄 geometry.py
📄 __init__.py
reste vide :
📄 format.py
contient une fonction percentage()
retournant le pourcentage associé à une fraction part/total
:
def percentage(part, total):
return f"{part / total * 100}%"
📄 geometry.py
contient :
- Une fonction
area_circle()
calculant l’aire d’un cercle. - Une fonction
area_square()
calculant l’aire d’un carré.
import math
def area_circle(radius):
return math.pi * radius * radius
def area_square(side):
return side * side
Importer un package
La méthode d’import de package varie selon le contenu du fichier d’initialisation 📄 __init__.py
.
Imports à la carte
Si 📄 __init__.py
est vide, il n’ajoute pas de fonctionnalités ou d’initialisation supplémentaires au package mais permet uniquement à Python de reconnaître le répertoire contenant ce fichier comme un package.
Ce code provoquera alors une erreur :
import math_utils
# ❌ Erreur => module 'math_utils' has no attribute 'geometry'
print(math_utils.geometry.area_circle(2))
Il faudra alors importer explicitement avec import
les modules souhaités :
import math_utils.geometry
print(math_utils.geometry.area_circle(2)) # ✅ OK
# ❌ Erreur => module 'math_utils' has no attribute 'format'
print(math_utils.format.percentage(2, 10))
L’usage du mot-clé from
propose la syntaxe alternative suivante :
from math_utils import geometry
print(geometry.area_circle(2))
L’utilisation de from
et import
combinés permet d’exploiter le module geometry sans avoir besoin de faire référence au package parent math_utils
à chaque appel de fonction. Cela simplifie l’accès aux fonctions du module tout en maintenant une bonne lisibilité du code.
Pré-imports
Il est également possible d’importer les modules relatifs à un package au niveau du fichier d’initialisation 📄 __init__.py
.
from math_utils.geometry import area_circle, area_square
from math_utils.format import percentage
Notation alternative (import relatif)
math_utils.geometry
constitue un import absolu car on précise directement le chemin complet du module à importer, en commençant par la racine du package (math_utils
).
Il est également possible d’écrire .geometry
, constituant un import relatif, où le point .
représente le package courant.
from .geometry import area_circle, area_square
from .format import percentage
Cela aura pour effet de rendre accessible depuis le paquet, l’ensemble des modules importés dans le 📄 __init__.py
, facilitant son usage :
import math_utils
print(math_utils.geometry.area_circle(2)) # ✅ OK
Il est même possible d’omettre le nom du module lors de l’appel d’une de ses composantes.
import math_utils
print(math_utils.area_circle(2)) # ✅ OK
Charger tous les modules
Le caractère *
permet de charger l’ensemble des éléments d’un module ou modules d’un package.
# Importer l'ensemble des modules d'un paquet
from math_utils import *
# Importer l'ensemble des éléments d'un module
from .geometry import *
S’il me paraît important de le préciser dans l’éventualité où vous rencontrez cette syntaxe un jour, cette approche reste à proscrire autant que possible dans un souci de clarté et de performance tout en limitant les conflits de noms.
Imports à la carte VS pré-imports
Voici un tableau résumant les avantages et inconvénients de l’importation, ou pas, de modules via le fichier 📄 __init__.py
:
Import | Description | Avantages | Inconvénients |
---|---|---|---|
Import à la carte | Le fichier 📄 __init__.py est présent mais ne contient aucun code d’importation. | - Le package est simple et léger. - Pas de risque de conflits de noms. - Moins de maintenance nécessaire pour le fichier d’initialisation. | - Nécessite des importations explicites pour chaque module lorsque utilisé ailleurs. - Peut compliquer l’accès aux modules du package. |
Pré-import | Le fichier 📄 __init__.py importe certains modules pour les exposer directement. | - Simplifie l’accès aux modules et fonctions du package. - Offre une interface plus propre et plus pratique. - Facilite la réorganisation des modules. | - Peut exposer plus de fonctions que nécessaire, entraînant des conflits de noms potentiels. - Augmente le risque d’importer des éléments non utilisés, ce qui peut alourdir le package. |
Alias
Lorsque vous importez un package ou un module, vous avez la possibilité de lui donner un alias. Cela aura pour effet de le renommer.
Alias de package
import math_utils as mu
print(mu.geometry.area_circle(2))
Alias de module
from math_utils import geometry as geo
print(geo.area_circle(2))