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 unites logiques reutilisables et d'eviter de tout mettre dans un seul fichier gigantesque.

Python dispose d'une bibliotheque standard tres riche : des centaines de modules prets a l'emploi couvrant les maths, les dates, les fichiers, le reseau, les expressions regulieres, 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 facon 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

Apres import math, toutes les fonctions et variables du module sont accessibles via la syntaxe math.nom.


Importer une fonction specifique : 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 evite de taper le nom du module a 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 particulierement utile pour les modules aux noms longs ou les bibliotheques tierces comme numpy (importe en np) ou pandas (importe en pd).


from module import * — a eviter

from math import * # Importe TOUT le contenu de math

print(sqrt(16)) # 4.0
print(pi) # 3.141592653589793
Attention - import *

Evitez from module import * car :

  • Cela pollue l'espace de noms avec des dizaines de noms inconnus
  • On ne sait plus d'ou vient chaque fonction
  • Des conflits de noms silencieux peuvent survenir
  • Le code devient difficile a lire et a maintenir

La bibliotheque standard : les modules essentiels

math — operations mathematiques

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 aleatoires

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 element au hasard
print(random.sample(nombres, 3)) # Choisit 3 elements sans repetition

random.seed(42) # Fixe la graine pour des resultats 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

# Durees
dans_une_semaine = aujourd_hui + timedelta(days=7)
print(dans_une_semaine)

# Calcul de difference
naissance = date(1990, 5, 20)
age = (aujourd_hui - naissance).days // 365
print(f"Age : {age} ans")

os — interactions avec le systeme d'exploitation

import os

# Repertoire courant
print(os.getcwd()) # /home/user/projets

# Lister les fichiers
print(os.listdir('.'))

# Verifier 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 — parametres et fonctions du systeme

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 = succes, autre = erreur

re — expressions regulieres

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 (numero de telephone)
pattern = r'^\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$'
print(bool(re.match(pattern, '06-12-34-56-78'))) # True

json — serialisation 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 donnees avancees

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 defaut
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 a droite
file.appendleft(0) # Ajoute a gauche
file.pop() # Retire a droite
file.popleft() # Retire a gauche
print(file) # deque([1, 2, 3])

Creer son propre module

Pour creer un module, il suffit de creer 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 meme 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 (meme vide) indique a 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 execute un fichier :

  • Si c'est le fichier principal lance directement : __name__ vaut "__main__"
  • Si c'est un module importe 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'execute QUE si on lance ce fichier directement
# Il ne s'execute PAS quand ce fichier est importe
if __name__ == "__main__":
demo()
print("Tests passes !")

Sans ce garde, le code de test s'executerait a chaque import du module, ce qui est tres indesirable.


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 specifique
pip install requests==2.31.0

# Mettre a jour un package
pip install --upgrade requests

# Desinstaller
pip uninstall requests

# Lister les packages installes
pip list

# Voir les infos d'un package
pip show requests

Environnements virtuels : venv

Un environnement virtuel isole les dependances de chaque projet. Sans venv, tous vos projets partagent les memes packages, ce qui cause des conflits de versions.

# Creer 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

# Desactiver
deactivate
Bonne pratique - venv

Creez toujours un environnement virtuel pour chaque projet. Ajoutez le dossier venv/ a votre .gitignore — il ne doit jamais etre commite car il est reconstitue depuis requirements.txt.


requirements.txt : les dependances du projet

# Generer le fichier avec les packages installes 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 dependances depuis le fichier
pip install -r requirements.txt

Ce fichier est essentiel pour que vos collegues ou un serveur puissent reconstruire exactement le meme environnement.


Exercices pratiques

Exercice 1 : Importer math et utiliser pi

Bonne pratique - Imports en tete 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 bibliotheque standard, puis les packages tiers, puis vos propres modules, separes par une ligne vide.


Exercice 2 : Utiliser random.randint()

Bonne pratique - Reproductibilite

Pour les tests ou simulations qui doivent donner les memes resultats, utilisez random.seed(42) avant vos appels aleatoires. Cela rend vos resultats reproductibles tout en conservant le comportement aleatoire pour la production.


Exercice 3 : Utiliser datetime.now()

Bonne pratique - Fuseaux horaires

datetime.now() retourne l'heure locale. Pour des applications web ou distribuees, utilisez datetime.utcnow() ou mieux, datetime.now(timezone.utc) avec from datetime import timezone. Stockez toujours vos dates en UTC dans les bases de donnees.


Exercice 4 : Utiliser os.path.exists()

Bonne pratique - Chemins portables

Utilisez toujours os.path.join() pour construire des chemins de fichiers. Cela garantit la compatibilite entre Linux/macOS (separateur /) et Windows (separateur \). Encore mieux : utilisez le module pathlib disponible depuis Python 3.4.


Exercice 5 : Le garde __name__ == "__main__"

Bonne pratique - Point d'entree

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'entree est identifiable immediatement).


Quiz de revision


Quelle instruction importe uniquement la fonction sqrt du module math ?


Pourquoi faut-il eviter 'from module import *' ?


Que vaut __name__ quand un fichier est importe comme module ?


Quelle commande cree un environnement virtuel Python ?


Quelle commande genere un fichier requirements.txt ?


Une solution