Les Modules Python
Qu'est-ce qu'un module ?
Un module est simplement un fichier .py contenant des fonctions, des classes et des variables. Les modules permettent d'organiser le code en unités logiques réutilisables et d'éviter de tout mettre dans un seul fichier gigantesque.
Python dispose d'une bibliothèque standard très riche : des centaines de modules prêts à l'emploi couvrant les maths, les dates, les fichiers, le réseau, les expressions régulières, et bien plus encore.
# mon_module.py (ceci est un module)
PI = 3.14159
def aire_cercle(rayon):
return PI * rayon ** 2
def perimetre_cercle(rayon):
return 2 * PI * rayon
Importer un module : import
La façon la plus simple d'utiliser un module est de l'importer avec import :
import math
print(math.pi) # 3.141592653589793
print(math.sqrt(25)) # 5.0
print(math.floor(3.7)) # 3
print(math.ceil(3.2)) # 4
Après import math, toutes les fonctions et variables du module sont accessibles via la syntaxe math.nom.
Importer une fonction spécifique : from ... import
Si vous n'avez besoin que d'une ou deux fonctions, vous pouvez les importer directement :
from math import sqrt, pi
print(sqrt(49)) # 7.0
print(pi) # 3.141592653589793
# Plus besoin d'ecrire math.sqrt ou math.pi
Cela évite de taper le nom du module à chaque fois.
Alias : import ... as
Vous pouvez renommer un module lors de l'import pour raccourcir son nom :
import datetime as dt
import collections as col
maintenant = dt.datetime.now()
print(maintenant)
compteur = col.Counter([1, 2, 2, 3, 3, 3])
print(compteur) # Counter({3: 2, 2: 2, 1: 1})
C'est particulièrement utile pour les modules aux noms longs ou les bibliothèques tierces comme numpy (importé en np) ou pandas (importé en pd).
from module import * — à éviter
from math import * # Importe TOUT le contenu de math
print(sqrt(16)) # 4.0
print(pi) # 3.141592653589793
Évitez from module import * car :
- Cela pollue l'espace de noms avec des dizaines de noms inconnus
- On ne sait plus d'où vient chaque fonction
- Des conflits de noms silencieux peuvent survenir
- Le code devient difficile à lire et à maintenir
La bibliothèque standard : les modules essentiels
math — opérations mathématiques
import math
print(math.pi) # 3.141592653589793
print(math.e) # 2.718281828459045
print(math.sqrt(144)) # 12.0
print(math.pow(2, 10)) # 1024.0
print(math.log(100, 10)) # 2.0
print(math.sin(math.pi/2)) # 1.0
print(math.factorial(5)) # 120
print(math.gcd(12, 8)) # 4
random — nombres aléatoires
import random
print(random.random()) # Flottant entre 0.0 et 1.0
print(random.randint(1, 6)) # Entier entre 1 et 6 inclus
print(random.uniform(0.0, 10.0)) # Flottant entre 0.0 et 10.0
nombres = [1, 2, 3, 4, 5]
random.shuffle(nombres) # Melange en place
print(nombres)
print(random.choice(nombres)) # Choisit un élément au hasard
print(random.sample(nombres, 3)) # Choisit 3 éléments sans répétition
random.seed(42) # Fixe la graine pour des résultats reproductibles
datetime — dates et heures
from datetime import datetime, date, timedelta
# Date et heure actuelles
maintenant = datetime.now()
print(maintenant) # 2024-01-15 10:30:45.123456
print(maintenant.year) # 2024
print(maintenant.strftime('%d/%m/%Y')) # 15/01/2024
# Date uniquement
aujourd_hui = date.today()
print(aujourd_hui) # 2024-01-15
# Durées
dans_une_semaine = aujourd_hui + timedelta(days=7)
print(dans_une_semaine)
# Calcul de différence
naissance = date(1990, 5, 20)
age = (aujourd_hui - naissance).days // 365
print(f"Age : {age} ans")
os — interactions avec le système d'exploitation
import os
# Répertoire courant
print(os.getcwd()) # /home/user/projets
# Lister les fichiers
print(os.listdir('.'))
# Vérifier l'existence
print(os.path.exists('mon_fichier.txt')) # True ou False
print(os.path.isfile('script.py')) # True si c'est un fichier
print(os.path.isdir('mon_dossier')) # True si c'est un dossier
# Construire des chemins (portable Mac/Linux/Windows)
chemin = os.path.join('dossier', 'sous-dossier', 'fichier.txt')
print(chemin) # dossier/sous-dossier/fichier.txt
# Variables d'environnement
print(os.environ.get('HOME'))
print(os.environ.get('DATABASE_URL', 'sqlite:///default.db'))
sys — paramètres et fonctions du système
import sys
print(sys.version) # Version de Python
print(sys.platform) # 'linux', 'darwin', 'win32'
print(sys.argv) # Arguments de la ligne de commande
print(sys.path) # Chemins de recherche des modules
# Quitter le programme
# sys.exit(0) # 0 = succès, autre = erreur
re — expressions régulières
import re
texte = "Mon email est alice@example.com et bob@test.fr"
# Rechercher un motif
match = re.search(r'\w+@\w+\.\w+', texte)
if match:
print(match.group()) # alice@example.com
# Trouver toutes les occurrences
emails = re.findall(r'\w+@\w+\.\w+', texte)
print(emails) # ['alice@example.com', 'bob@test.fr']
# Remplacer
resultat = re.sub(r'\d+', 'X', "Il y a 3 chats et 12 chiens")
print(resultat) # Il y a X chats et X chiens
# Valider un format (numéro de téléphone)
pattern = r'^\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$'
print(bool(re.match(pattern, '06-12-34-56-78'))) # True
json — sérialisation JSON
import json
# Dict Python vers JSON
data = {'nom': 'Alice', 'age': 25, 'langages': ['Python', 'JS']}
json_str = json.dumps(data, indent=2)
print(json_str)
# JSON vers dict Python
texte_json = '{"ville": "Paris", "population": 2161000}'
obj = json.loads(texte_json)
print(obj['ville']) # Paris
# Lire/ecrire un fichier JSON
with open('config.json', 'w') as f:
json.dump(data, f, indent=2)
with open('config.json', 'r') as f:
config = json.load(f)
collections — structures de données avancées
from collections import Counter, defaultdict, OrderedDict, deque
# Counter : compter les occurrences
mots = ['chat', 'chien', 'chat', 'oiseau', 'chat', 'chien']
compteur = Counter(mots)
print(compteur) # Counter({'chat': 3, 'chien': 2, 'oiseau': 1})
print(compteur.most_common(2)) # [('chat', 3), ('chien', 2)]
# defaultdict : dict avec valeur par défaut
scores = defaultdict(list)
scores['Alice'].append(90)
scores['Alice'].append(85)
scores['Bob'].append(70)
print(dict(scores)) # {'Alice': [90, 85], 'Bob': [70]}
# deque : file/pile double
file = deque([1, 2, 3])
file.append(4) # Ajoute à droite
file.appendleft(0) # Ajoute à gauche
file.pop() # Retire à droite
file.popleft() # Retire à gauche
print(file) # deque([1, 2, 3])
Créer son propre module
Pour créer un module, il suffit de créer un fichier .py :
# geometrie.py
PI = 3.14159265
def aire_cercle(rayon):
"""Calcule l'aire d'un cercle."""
return PI * rayon ** 2
def aire_rectangle(largeur, hauteur):
"""Calcule l'aire d'un rectangle."""
return largeur * hauteur
def aire_triangle(base, hauteur):
"""Calcule l'aire d'un triangle."""
return 0.5 * base * hauteur
Puis dans un autre fichier du même dossier :
# main.py
import geometrie
print(geometrie.aire_cercle(5)) # 78.53981625
print(geometrie.aire_rectangle(4, 6)) # 24
from geometrie import aire_triangle
print(aire_triangle(3, 8)) # 12.0
Packages : organiser ses modules
Un package est un dossier contenant un fichier __init__.py et d'autres modules.
mon_projet/
main.py
utilitaires/
__init__.py
calculs.py
formatage.py
validation.py
Le fichier __init__.py (même vide) indique à Python que ce dossier est un package.
# utilitaires/calculs.py
def additionner(a, b):
return a + b
# main.py
from utilitaires.calculs import additionner
from utilitaires import formatage
print(additionner(3, 5)) # 8
Le garde if __name__ == "__main__":
C'est l'un des motifs les plus importants en Python. Comprendre pourquoi requiert de comprendre la variable __name__.
Quand Python exécute un fichier :
- Si c'est le fichier principal lancé directement :
__name__vaut"__main__" - Si c'est un module importé par un autre fichier :
__name__vaut le nom du fichier
# utilitaires.py
def calculer_tva(prix):
return prix * 0.20
def demo():
print("Demo TVA:", calculer_tva(100))
# Ce bloc ne s'exécute QUE si on lance ce fichier directement
# Il ne s'exécute PAS quand ce fichier est importé
if __name__ == "__main__":
demo()
print("Tests passes !")
Sans ce garde, le code de test s'exécuterait à chaque import du module, ce qui est très indésirable.
Installer des packages tiers : pip
pip est le gestionnaire de packages de Python. Il permet d'installer des milliers de packages depuis PyPI.
# Installer un package
pip install requests
# Installer une version spécifique
pip install requests==2.31.0
# Mettre à jour un package
pip install --upgrade requests
# Désinstaller
pip uninstall requests
# Lister les packages installés
pip list
# Voir les infos d'un package
pip show requests
Environnements virtuels : venv
Un environnement virtuel isole les dépendances de chaque projet. Sans venv, tous vos projets partagent les mêmes packages, ce qui cause des conflits de versions.
# Créer un environnement virtuel
python -m venv venv
# Activer (Linux / macOS)
source venv/bin/activate
# Activer (Windows)
venv\Scripts\activate
# Vous verrez (venv) dans votre terminal
(venv) $ pip install flask
# Désactiver
deactivate
Créez toujours un environnement virtuel pour chaque projet. Ajoutez le dossier venv/ à votre .gitignore — il ne doit jamais être commité car il est reconstitué depuis requirements.txt.
requirements.txt : les dépendances du projet
# Générer le fichier avec les packages installés et leurs versions
pip freeze > requirements.txt
# Contenu typique de requirements.txt :
# flask==3.0.0
# requests==2.31.0
# python-dotenv==1.0.0
# Installer toutes les dépendances depuis le fichier
pip install -r requirements.txt
Ce fichier est essentiel pour que vos collègues ou un serveur puissent reconstruire exactement le même environnement.
Exercices pratiques
Exercice 1 : Importer math et utiliser pi
Placez toujours vos imports en haut du fichier, avant tout autre code. C'est la convention PEP 8 : d'abord les modules de la bibliothèque standard, puis les packages tiers, puis vos propres modules, séparés par une ligne vide.
Exercice 2 : Utiliser random.randint()
Pour les tests ou simulations qui doivent donner les mêmes résultats, utilisez random.seed(42) avant vos appels aléatoires. Cela rend vos résultats reproductibles tout en conservant le comportement aléatoire pour la production.
Exercice 3 : Utiliser datetime.now()
datetime.now() retourne l'heure locale. Pour des applications web ou distribuées, utilisez datetime.utcnow() ou mieux, datetime.now(timezone.utc) avec from datetime import timezone. Stockez toujours vos dates en UTC dans les bases de données.
Exercice 4 : Utiliser os.path.exists()
Utilisez toujours os.path.join() pour construire des chemins de fichiers. Cela garantit la compatibilité entre Linux/macOS (séparateur /) et Windows (séparateur \). Encore mieux : utilisez le module pathlib disponible depuis Python 3.4.
Exercice 5 : Le garde __name__ == "__main__"
Encapsulez toujours le code de lancement dans une fonction main() et appelez-la via le garde if __name__ == "__main__":. Cela rend votre code testable (on peut importer sans effets de bord) et clair (le point d'entrée est identifiable immédiatement).