Aller au contenu principal

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
Attention - import *

É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
Bonne pratique - venv

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

Bonne pratique - Imports en tête de fichier

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()

Bonne pratique - Reproductibilité

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()

Bonne pratique - Fuseaux horaires

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()

Bonne pratique - Chemins portables

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__"

Bonne pratique - Point d'entrée

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).


Quiz de révision


Quelle instruction importe uniquement la fonction sqrt du module math ?


Pourquoi faut-il éviter 'from module import *' ?


Que vaut __name__ quand un fichier est importé comme module ?


Quelle commande crée un environnement virtuel Python ?


Quelle commande génère un fichier requirements.txt ?


📌 Une solution