Python & AI Tutorials Logo
Programmation Python

39. Modules essentiels de la bibliothèque standard

La bibliothèque standard (standard library) de Python est un ensemble de modules intégrés à Python — vous n’avez rien à installer en plus pour les utiliser. Ces modules fournissent des outils puissants pour des tâches de programmation courantes : générer des nombres aléatoires, manipuler des dates et des heures, échanger des données avec d’autres programmes, et utiliser des structures de données spécialisées qui vont au-delà des listes (list) et des dictionnaires (dict) de base.

Dans ce chapitre, nous allons explorer cinq modules essentiels de la bibliothèque standard que vous utiliserez fréquemment en programmation Python dans le monde réel.

39.1) Générer du hasard avec random

Le module random fournit des fonctions pour générer des nombres aléatoires et effectuer des sélections aléatoires. C’est utile pour les simulations, les jeux, les tests, l’échantillonnage de données, et toute situation où vous avez besoin d’un comportement imprévisible.

39.1.1) Générer des entiers aléatoires avec randint()

La fonction randint() génère un entier aléatoire entre deux valeurs, inclusives aux deux extrémités :

python
import random
 
# Simuler un lancer de dé à six faces
die_roll = random.randint(1, 6)
print(f"You rolled: {die_roll}")  # Output: You rolled: 4 (varies each run)
 
# Générer un âge aléatoire entre 18 et 65
age = random.randint(18, 65)
print(f"Random age: {age}")  # Output: Random age: 42 (varies)

Remarquez que les valeurs de début et de fin sont toutes deux incluses dans les résultats possibles. randint(1, 6) peut renvoyer 1, 2, 3, 4, 5 ou 6 — les six valeurs sont possibles.

Voici un exemple pratique qui simule plusieurs lancers de dés :

python
import random
 
# Simuler le lancer de deux dés et calculer leur somme
die1 = random.randint(1, 6)
die2 = random.randint(1, 6)
total = die1 + die2
 
print(f"Die 1: {die1}")  # Output: Die 1: 3 (varies)
print(f"Die 2: {die2}")  # Output: Die 2: 5 (varies)
print(f"Total: {total}")  # Output: Total: 8 (varies)
 
if total == 7:
    print("Lucky seven!")
elif total == 2 or total == 12:
    print("Snake eyes or boxcars!")

Pourquoi les deux extrémités sont inclusives : cela rend randint() intuitif pour des cas d’usage courants. Quand vous voulez un nombre de 1 à 6 (comme un dé), vous écrivez randint(1, 6) et 1 comme 6 sont des résultats possibles.

39.1.2) Générer des nombres à virgule flottante aléatoires

Pour des nombres décimaux aléatoires, utilisez random() (renvoie un float entre 0.0 et 1.0) ou uniform() (renvoie un float entre deux valeurs spécifiées) :

python
import random
 
# Générer un float aléatoire entre 0.0 et 1.0 (0.0 inclus, 1.0 exclu)
probability = random.random()
print(f"Random probability: {probability:.4f}")  # Output: Random probability: 0.7284 (varies)
 
# Générer une température aléatoire entre 15.0 et 30.0 degrés
temperature = random.uniform(15.0, 30.0)
print(f"Temperature: {temperature:.2f}°C")  # Output: Temperature: 23.47°C (varies)
 
# Générer un prix aléatoire entre 10,00 $ et 99,99 $
price = random.uniform(10.0, 99.99)
print(f"Price: ${price:.2f}")  # Output: Price: $45.67 (varies)

La fonction random() est utile quand vous avez besoin d’une valeur de probabilité ou d’un pourcentage. La fonction uniform() est meilleure quand vous avez besoin d’un nombre décimal aléatoire dans une plage précise.

39.1.3) Faire des choix aléatoires avec choice()

La fonction choice() sélectionne aléatoirement un élément dans une séquence (liste (list), tuple ou chaîne) :

python
import random
 
# Sélectionner une couleur au hasard
colors = ["red", "blue", "green", "yellow", "purple"]
selected_color = random.choice(colors)
print(f"Selected color: {selected_color}")  # Output: Selected color: green (varies)
 
# Sélectionner un gagnant au hasard parmi les participants
participants = ["Alice", "Bob", "Charlie", "Diana"]
winner = random.choice(participants)
print(f"The winner is: {winner}")  # Output: The winner is: Bob (varies)
 
# Sélectionner un caractère au hasard dans une chaîne
vowels = "aeiou"
random_vowel = random.choice(vowels)
print(f"Random vowel: {random_vowel}")  # Output: Random vowel: i (varies)

C’est particulièrement utile pour les jeux, l’échantillonnage aléatoire, ou la sélection de données de test aléatoires. Chaque élément de la séquence a une probabilité égale d’être choisi.

Voici un exemple plus complexe qui simule un jeu de quiz simple :

python
import random
 
# Questions de quiz avec leurs réponses
questions = [
    ("What is 2 + 2?", "4"),
    ("What is the capital of France?", "Paris"),
    ("What color is the sky?", "blue")
]
 
# Sélectionner une question au hasard
question, correct_answer = random.choice(questions)
print(f"Question: {question}")
 
user_answer = input("Your answer: ")
if user_answer.lower() == correct_answer.lower():
    print("Correct!")
else:
    print(f"Wrong! The answer was: {correct_answer}")

39.1.4) Sélectionner plusieurs éléments aléatoires avec sample()

Quand vous devez sélectionner plusieurs éléments uniques dans une séquence, utilisez sample(). C’est comme piocher des cartes dans un paquet sans remise — une fois qu’un élément est sélectionné, il ne sera pas sélectionné à nouveau :

python
import random
 
# Sélectionner 3 élèves au hasard pour un projet de groupe
students = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"]
group = random.sample(students, 3)
print(f"Group members: {group}")  # Output: Group members: ['Diana', 'Alice', 'Frank'] (varies)
 
# Tirer 5 numéros de loto de 1 à 50 (sans doublons)
lottery_numbers = random.sample(range(1, 51), 5)
lottery_numbers.sort()  # Trier pour l'affichage
print(f"Lottery numbers: {lottery_numbers}")  # Output: Lottery numbers: [7, 15, 23, 38, 49] (varies)

Le deuxième argument de sample() indique combien d’éléments sélectionner. Le nombre doit être inférieur ou égal à la longueur de la séquence — vous ne pouvez pas sélectionner plus d’éléments qu’il n’en existe.

39.1.5) Mélanger des séquences avec shuffle()

La fonction shuffle() réordonne aléatoirement les éléments d’une liste (list) sur place (en modifiant la liste d’origine) :

python
import random
 
# Mélanger un paquet de cartes
cards = ["A♠", "K♠", "Q♠", "J♠", "10♠", "9♠", "8♠", "7♠"]
print(f"Original: {cards}")
random.shuffle(cards)
print(f"Shuffled: {cards}")  # Output: Shuffled: ['Q♠', '7♠', 'A♠', '10♠', '9♠', 'J♠', 'K♠', '8♠'] (varies)
 
# Mélanger les questions du quiz pour un ordre aléatoire
questions = ["Question 1", "Question 2", "Question 3", "Question 4"]
random.shuffle(questions)
print(f"Randomized order: {questions}")  # Output: Randomized order: ['Question 3', 'Question 1', 'Question 4', 'Question 2'] (varies)

Fonctions du module Random

randint : Entiers aléatoires

random/uniform : Floats aléatoires

choice : Choisir un élément

sample : Choisir plusieurs éléments uniques

shuffle : Réordonner la liste sur place

Inclusif aux deux extrémités

random : 0.0 à 1.0

uniform : Plage personnalisée

Probabilité égale pour chacun

Pas de doublons

Modifie la liste d’origine

39.2) Travailler avec des dates et des heures

Le module datetime fournit des classes pour travailler avec des dates, des heures et des intervalles de temps. C’est essentiel pour la planification, la journalisation, le calcul de durées et toute application qui doit suivre quand les choses se produisent.

39.2.1) Obtenir la date et l’heure actuelles

La classe datetime représente un instant précis avec des composants de date et d’heure :

python
from datetime import datetime
 
# Obtenir la date et l’heure actuelles
now = datetime.now()
print(f"Current datetime: {now}")
# Output: Current datetime: 2026-01-02 14:30:45.123456
 
# Accéder aux composants individuels
print(f"Year: {now.year}")      # Output: Year: 2026
print(f"Month: {now.month}")    # Output: Month: 1
print(f"Day: {now.day}")        # Output: Day: 2
print(f"Hour: {now.hour}")      # Output: Hour: 14
print(f"Minute: {now.minute}")  # Output: Minute: 30
print(f"Second: {now.second}")  # Output: Second: 45

Pour obtenir seulement la date (sans l’heure), utilisez la classe date :

python
from datetime import date
 
# Obtenir la date du jour
today = date.today()
print(f"Today: {today}")  # Output: Today: 2026-01-02
 
print(f"Year: {today.year}")    # Output: Year: 2026
print(f"Month: {today.month}")  # Output: Month: 1
print(f"Day: {today.day}")      # Output: Day: 2

39.2.2) Créer des dates et heures spécifiques

Vous pouvez créer des objets datetime et date pour des instants précis :

python
from datetime import datetime, date
 
# Créer une date spécifique
birthday = date(1995, 7, 15)
print(f"Birthday: {birthday}")  # Output: Birthday: 1995-07-15
 
# Créer un datetime spécifique
meeting = datetime(2026, 3, 15, 14, 30)  # 15 mars 2026 à 14h30
print(f"Meeting: {meeting}")  # Output: Meeting: 2026-03-15 14:30:00

C’est utile pour représenter des échéances, des rendez-vous, des dates historiques ou tout point fixe dans le temps :

python
from datetime import date
 
# Dates importantes dans un projet
project_start = date(2026, 1, 15)
project_end = date(2026, 6, 30)
 
print(f"Project duration: {project_start} to {project_end}")
# Output: Project duration: 2026-01-15 to 2026-06-30

39.2.3) Calculer des différences de temps avec timedelta

La classe timedelta représente une durée — la différence entre deux dates ou heures. Vous pouvez l’utiliser pour calculer le temps écoulé ou pour ajouter/soustraire du temps à des dates :

python
from datetime import date, timedelta
 
# Calculer l’âge
birth_date = date(1995, 7, 15)
today = date(2026, 1, 2)
age_delta = today - birth_date
 
print(f"Days since birth: {age_delta.days}")  # Output: Days since birth: 11128
print(f"Years (approximate): {age_delta.days // 365}")  # Output: Years (approximate): 30

Quand vous soustrayez une date à une autre, vous obtenez un objet timedelta. L’attribut days vous donne le nombre de jours dans cette durée.

Vous pouvez aussi créer des objets timedelta directement pour représenter des durées spécifiques :

python
from datetime import date, timedelta
 
# Ajouter des jours à une date
today = date(2026, 1, 2)
one_week = timedelta(days=7)
next_week = today + one_week
 
print(f"Today: {today}")        # Output: Today: 2026-01-02
print(f"Next week: {next_week}")  # Output: Next week: 2026-01-09
 
# Soustraire des jours à une date
thirty_days_ago = today - timedelta(days=30)
print(f"30 days ago: {thirty_days_ago}")  # Output: 30 days ago: 2025-12-03

timedelta peut représenter des jours, secondes, microsecondes, millisecondes, minutes, heures et semaines :

python
from datetime import datetime, timedelta
 
# Calculer une échéance
now = datetime(2026, 1, 2, 14, 30)
deadline = now + timedelta(hours=48, minutes=30)
 
print(f"Current time: {now}")    # Output: Current time: 2026-01-02 14:30:00
print(f"Deadline: {deadline}")   # Output: Deadline: 2026-01-04 15:00:00
 
# Calculer le temps restant
time_left = deadline - now
print(f"Hours remaining: {time_left.total_seconds() / 3600}")  # Output: Hours remaining: 48.5

La méthode total_seconds() convertit la durée entière en secondes, que vous pouvez ensuite convertir en heures, minutes ou toute autre unité.

Voici un exemple pratique de calcul de jalons de projet :

python
from datetime import date, timedelta
 
# Planification du projet
project_start = date(2026, 1, 15)
sprint_duration = timedelta(weeks=2)
 
sprint_1_end = project_start + sprint_duration
sprint_2_end = sprint_1_end + sprint_duration
sprint_3_end = sprint_2_end + sprint_duration
 
print(f"Sprint 1: {project_start} to {sprint_1_end}")
# Output: Sprint 1: 2026-01-15 to 2026-01-29
print(f"Sprint 2: {sprint_1_end} to {sprint_2_end}")
# Output: Sprint 2: 2026-01-29 to 2026-02-12
print(f"Sprint 3: {sprint_2_end} to {sprint_3_end}")
# Output: Sprint 3: 2026-02-12 to 2026-02-26

39.2.4) Comparer des dates et des heures

Les objets date et datetime peuvent être comparés avec les opérateurs de comparaison standard :

python
from datetime import date
 
# Comparer des dates
date1 = date(2026, 1, 15)
date2 = date(2026, 2, 20)
date3 = date(2026, 1, 15)
 
print(date1 < date2)   # Output: True
print(date1 == date3)  # Output: True
print(date2 > date1)   # Output: True

C’est utile pour vérifier des échéances, valider des plages de dates, et trier des dates :

python
from datetime import date
 
# Vérifier si une date est passée
event_date = date(2025, 12, 25)
today = date(2026, 1, 2)
 
if event_date < today:
    print("This event has already passed")  # Output: This event has already passed
else:
    print("This event is upcoming")
 
# Trier une liste de dates
important_dates = [
    date(2026, 3, 15),
    date(2026, 1, 10),
    date(2026, 2, 28)
]
 
important_dates.sort()
print("Dates in order:")  # Output: Dates in order:
for d in important_dates:
    print(f"  {d}")
# Output:
#   2026-01-10
#   2026-02-28
#   2026-03-15

39.2.5) Formater des dates et des heures avec strftime()

La méthode strftime() (string format time) convertit des dates et des heures en chaînes formatées. Vous spécifiez le format à l’aide de codes spéciaux :

python
from datetime import datetime
 
now = datetime(2026, 1, 2, 14, 30, 45)
 
# Formats de date courants
print(now.strftime("%Y-%m-%d"))           # Output: 2026-01-02
print(now.strftime("%m/%d/%Y"))           # Output: 01/02/2026
print(now.strftime("%B %d, %Y"))          # Output: January 02, 2026
print(now.strftime("%A, %B %d, %Y"))      # Output: Friday, January 02, 2026
 
# Formats d’heure courants
print(now.strftime("%H:%M:%S"))           # Output: 14:30:45
print(now.strftime("%I:%M %p"))           # Output: 02:30 PM
 
# Formats combinés
print(now.strftime("%Y-%m-%d %H:%M:%S"))  # Output: 2026-01-02 14:30:45
print(now.strftime("%B %d, %Y at %I:%M %p"))  # Output: January 02, 2026 at 02:30 PM

Codes de format courants :

CodeDescriptionExemple
%YAnnée avec siècle2026
%mMois en nombre avec zéro initial (01-12)01
%dJour en nombre avec zéro initial (01-31)02
%BNom complet du moisJanuary
%bNom abrégé du moisJan
%ANom complet du jour de la semaineFriday
%aNom abrégé du jour de la semaineFri
%HHeure au format 24 h (00-23)14
%IHeure au format 12 h (01-12)02
%MMinute (00-59)30
%SSeconde (00-59)45
%pAM/PMPM

Voici un exemple pratique de création d’une entrée de journal :

python
from datetime import datetime
 
def log_event(message):
    """Journaliser un événement avec un horodatage"""
    now = datetime.now()
    timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
    print(f"[{timestamp}] {message}")
 
log_event("User logged in")
# Output: [2026-01-02 14:30:45] User logged in
 
log_event("File uploaded successfully")
# Output: [2026-01-02 14:30:45] File uploaded successfully

39.2.6) Analyser des dates depuis des chaînes avec strptime()

La fonction strptime() (string parse time) convertit des chaînes formatées en objets datetime. Vous spécifiez les mêmes codes de format pour indiquer à Python comment interpréter la chaîne :

python
from datetime import datetime
 
# Analyser différents formats de date
date_str1 = "2026-01-15"
date1 = datetime.strptime(date_str1, "%Y-%m-%d")
print(f"Parsed: {date1}")  # Output: Parsed: 2026-01-15 00:00:00
 
date_str2 = "January 15, 2026"
date2 = datetime.strptime(date_str2, "%B %d, %Y")
print(f"Parsed: {date2}")  # Output: Parsed: 2026-01-15 00:00:00
 
# Analyser un datetime avec l’heure
datetime_str = "2026-01-15 14:30:00"
dt = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S")
print(f"Parsed: {dt}")  # Output: Parsed: 2026-01-15 14:30:00

C’est essentiel lorsque vous lisez des dates depuis des fichiers, des saisies utilisateur, ou des sources de données externes :

python
from datetime import datetime
 
# Analyser la saisie utilisateur
user_input = "03/15/2026"
try:
    event_date = datetime.strptime(user_input, "%m/%d/%Y")
    print(f"Event scheduled for: {event_date.strftime('%B %d, %Y')}")
    # Output: Event scheduled for: March 15, 2026
except ValueError:
    print("Invalid date format. Please use MM/DD/YYYY")

Important : la chaîne de format doit correspondre exactement à la chaîne d’entrée, sinon vous obtiendrez une ValueError :

python
from datetime import datetime
 
# Cela va échouer - le format ne correspond pas
try:
    datetime.strptime("2026-01-15", "%m/%d/%Y")  # Format incorrect
except ValueError as e:
    print(f"Error: {e}")
    # Output: Error: time data '2026-01-15' does not match format '%m/%d/%Y'

Module datetime

datetime.now : Date/heure actuelles

date.today : Date du jour

datetime/date : Créer des dates spécifiques

timedelta : Durées

strftime : Formater en chaîne

strptime : Analyser depuis une chaîne

Ajouter/soustraire aux dates

Calculer des différences

%Y, %m, %d, %H, %M, %S

Doit correspondre exactement au format

39.3) Lire et écrire des données JSON

JSON (JavaScript Object Notation) est un format texte pour stocker et échanger des données structurées. C’est le format le plus courant pour les API web, les fichiers de configuration et l’échange de données entre programmes. Le module json de Python facilite la conversion entre les structures de données Python et le texte JSON.

39.3.1) Comprendre la structure JSON

JSON ressemble aux dictionnaires (dict) et aux listes (list) Python, mais avec quelques différences :

JSON prend en charge ces types de données :

  • Objets (comme les dictionnaires Python) : {"name": "Alice", "age": 30}
  • Tableaux (comme les listes Python) : [1, 2, 3, 4]
  • Chaînes : "hello" (doivent utiliser des guillemets doubles)
  • Nombres : 42, 3.14
  • Booléens : true, false (en minuscules)
  • Null : null (comme le None de Python)

Différences clés par rapport à Python :

  • JSON utilise true/false/null au lieu de True/False/None de Python
  • Les chaînes JSON doivent utiliser des guillemets doubles ("text"), pas des guillemets simples
  • JSON ne prend pas en charge directement les tuples, les sets ou les objets personnalisés

Voici à quoi ressemblent des données JSON :

json
{
    "name": "Alice Johnson",
    "age": 30,
    "email": "alice@example.com",
    "is_active": true,
    "scores": [85, 92, 78, 95],
    "address": {
        "street": "123 Main St",
        "city": "Springfield",
        "zip": "12345"
    }
}

Remarque : il s’agit de texte JSON pur, pas de code Python. Remarquez le true en minuscules et l’utilisation des guillemets doubles.

39.3.2) Convertir des données Python en JSON avec dumps()

La fonction dumps() (dump string) convertit des structures de données Python en chaînes au format JSON :

python
import json
 
student = {
    "name": "Alice Johnson",
    "age": 30,
    "email": "alice@example.com",
    "is_active": True,
    "scores": [85, 92, 78, 95]
}
 
# Convertir un dictionnaire en JSON
json_string = json.dumps(student)
print(json_string)
# Output: {"name": "Alice Johnson", "age": 30, "email": "alice@example.com", "is_active": true, "scores": [85, 92, 78, 95]}
 
print(type(json_string))  # Output: <class 'str'>

Remarquez comment le True de Python est devenu true en JSON dans la sortie. La fonction dumps() gère automatiquement ces conversions.

Pour une sortie plus lisible, utilisez le paramètre indent :

python
import json
 
student = {
    "name": "Alice Johnson",
    "age": 30,
    "scores": [85, 92, 78, 95]
}
 
# Affichage joli avec indentation
json_string = json.dumps(student, indent=2)
print(json_string)
# Output:
# {
#   "name": "Alice Johnson",
#   "age": 30,
#   "scores": [
#     85,
#     92,
#     78,
#     95
#   ]
# }

Le paramètre indent indique combien d’espaces utiliser pour chaque niveau d’indentation. Cela rend le JSON beaucoup plus facile à lire, surtout pour des structures imbriquées complexes.

39.3.3) Convertir du JSON en données Python avec loads()

La fonction loads() (load string) convertit des chaînes au format JSON en structures de données Python :

python
import json
 
# Chaîne JSON (comme vous pourriez en recevoir depuis une API web)
json_string = '{"name": "Bob Smith", "age": 25, "scores": [90, 88, 92]}'
 
# Convertir en dictionnaire Python
student = json.loads(json_string)
print(student)  # Output: {'name': 'Bob Smith', 'age': 25, 'scores': [90, 88, 92]}
print(type(student))  # Output: <class 'dict'>
 
# Accéder aux données comme n’importe quel dictionnaire Python
print(f"Name: {student['name']}")  # Output: Name: Bob Smith
print(f"Average score: {sum(student['scores']) / len(student['scores'])}")
# Output: Average score: 90.0

Les true, false et null de JSON sont automatiquement convertis en True, False et None en Python :

python
import json
 
json_string = '{"active": true, "verified": false, "middle_name": null}'
data = json.loads(json_string)
 
print(data)  # Output: {'active': True, 'verified': False, 'middle_name': None}
print(type(data["active"]))  # Output: <class 'bool'>
print(type(data["middle_name"]))  # Output: <class 'NoneType'>

39.3.4) Écrire du JSON dans des fichiers avec dump()

La fonction dump() écrit des données Python directement dans un fichier au format JSON :

python
import json
 
# Dossiers d’étudiants
students = [
    {"name": "Alice", "age": 20, "gpa": 3.8},
    {"name": "Bob", "age": 22, "gpa": 3.5},
    {"name": "Charlie", "age": 21, "gpa": 3.9}
]
 
# Écrire dans un fichier JSON
with open("students.json", "w") as file:
    json.dump(students, file, indent=2)
 
print("Data written to students.json")
# Output: Data written to students.json

Après exécution de ce code, le fichier students.json contient :

json
[
  {
    "name": "Alice",
    "age": 20,
    "gpa": 3.8
  },
  {
    "name": "Bob",
    "age": 22,
    "gpa": 3.5
  },
  {
    "name": "Charlie",
    "age": 21,
    "gpa": 3.9
  }
]

Pourquoi utiliser dump() plutôt que dumps() ? La fonction dump() écrit directement dans un fichier, ce qui est plus efficace que de convertir d’abord en chaîne puis d’écrire la chaîne. Utilisez dump() pour les fichiers et dumps() quand vous avez besoin du JSON sous forme de chaîne (par exemple, pour l’envoyer sur un réseau).

39.3.5) Lire du JSON depuis des fichiers avec load()

La fonction load() lit des données JSON depuis un fichier et les convertit en structures de données Python :

python
import json
 
# Lire depuis le fichier JSON que nous avons créé plus tôt
with open("students.json", "r") as file:
    students = json.load(file)
 
print(f"Loaded {len(students)} students")  # Output: Loaded 3 students
 
# Travailler avec les données
for student in students:
    print(f"{student['name']}: GPA {student['gpa']}")
# Output:
# Alice: GPA 3.8
# Bob: GPA 3.5
# Charlie: GPA 3.9

39.3.6) Gérer les erreurs JSON

Lorsque vous travaillez avec JSON, vous pouvez rencontrer des données invalides. Gérez toujours les erreurs potentielles :

python
import json
 
# JSON invalide - guillemet de fermeture manquant
invalid_json = '{"name": "Alice", "age": 30'
 
try:
    data = json.loads(invalid_json)
except json.JSONDecodeError as e:
    print(f"Invalid JSON: {e}")
    # Output: Invalid JSON: Expecting ',' delimiter: line 1 column 28 (char 27)

C’est particulièrement important lorsque vous lisez du JSON depuis des sources externes (fichiers, API web, saisie utilisateur) où vous ne pouvez pas garantir que les données sont valides :

python
import json
 
def load_config(filename):
    """Charger une configuration depuis un fichier JSON avec gestion des erreurs"""
    try:
        with open(filename, "r") as file:
            config = json.load(file)
            return config
    except FileNotFoundError:
        print(f"Config file '{filename}' not found")
        return None
    except json.JSONDecodeError as e:
        print(f"Invalid JSON in '{filename}': {e}")
        return None
 
# Essayer de charger la configuration
config = load_config("config.json")
if config:
    print(f"Configuration loaded: {config}")
else:
    print("Using default configuration")

39.3.7) Exemple JSON pratique : sauvegarder et charger l’état d’une application

Voici un exemple complet montrant comment sauvegarder et charger des données d’application :

python
import json
 
def save_game_state(filename, player_data):
    """Sauvegarder l’état du jeu dans un fichier JSON"""
    with open(filename, "w") as file:
        json.dump(player_data, file, indent=2)
    print(f"Game saved to {filename}")
 
def load_game_state(filename):
    """Charger l’état du jeu depuis un fichier JSON"""
    try:
        with open(filename, "r") as file:
            player_data = json.load(file)
        print(f"Game loaded from {filename}")
        return player_data
    except FileNotFoundError:
        print("No saved game found")
        return None
 
# Données du jeu
player = {
    "name": "Hero",
    "level": 5,
    "health": 85,
    "inventory": ["sword", "shield", "potion"],
    "position": {"x": 10, "y": 20}
}
 
# Sauvegarder la partie
save_game_state("savegame.json", player)
# Output: Game saved to savegame.json
 
# Plus tard, charger la partie
loaded_player = load_game_state("savegame.json")
# Output: Game loaded from savegame.json
 
if loaded_player:
    print(f"Welcome back, {loaded_player['name']}!")
    print(f"Level: {loaded_player['level']}, Health: {loaded_player['health']}")
    # Output:
    # Welcome back, Hero!
    # Level: 5, Health: 85

Module json

dumps : Python → chaîne JSON

loads : chaîne JSON → Python

dump : Python → fichier JSON

load : fichier JSON → Python

paramètre indent pour la lisibilité

Gère les conversions de types

Plus efficace que dumps + write

Gérer JSONDecodeError

39.4) Conteneurs pratiques dans collections

Le module collections fournit des types de conteneurs spécialisés qui étendent les conteneurs intégrés de Python (listes (list), dictionnaires (dict), sets) avec des fonctionnalités supplémentaires. Ces conteneurs résolvent des problèmes courants de manière plus élégante que l’utilisation de structures de données de base.

39.4.1) Compter des éléments avec Counter

La classe Counter est conçue pour compter des objets hachables. C’est une sous-classe de dictionnaire (dict) qui stocke les éléments comme clés et leurs nombres d’occurrences comme valeurs.

Ce que Counter accepte en entrée :

  • Tout itérable (liste (list), chaîne, tuple, etc.)
  • Un autre dictionnaire avec des comptes
  • Des arguments nommés avec des comptes

Ce que Counter stocke :

  • Un dictionnaire où les clés sont les éléments et les valeurs sont leurs comptes
  • Exemple : Counter(['a', 'b', 'a']) stocke {'a': 2, 'b': 1}

Avantage clé par rapport aux dictionnaires classiques :

  • Renvoie 0 pour les clés manquantes au lieu de lever KeyError
  • Fournit des méthodes spécifiques au comptage comme most_common()
  • Prend en charge des opérations arithmétiques entre compteurs

Utilisation de base

python
from collections import Counter
 
# Compter les lettres dans un mot
word = "mississippi"
letter_counts = Counter(word)
print(letter_counts)
# Output: Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
 
# Accéder aux comptes comme un dictionnaire
print(f"Number of 'i's: {letter_counts['i']}")
# Output: Number of 'i's: 4
 
print(f"Number of 'z's: {letter_counts['z']}")
# Output: Number of 'z's: 0 (returns 0 for missing keys, no KeyError!)

Créer des Counters à partir de différentes sources

python
from collections import Counter
 
# Depuis une liste
votes = ["Alice", "Bob", "Alice", "Charlie", "Alice", "Bob", "Alice"]
vote_counts = Counter(votes)
print(vote_counts)
# Output: Counter({'Alice': 4, 'Bob': 2, 'Charlie': 1})
 
# Depuis une chaîne (compte chaque caractère)
letter_counts = Counter("hello")
print(letter_counts)
# Output: Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
 
# Depuis un dictionnaire
existing_counts = {'apple': 3, 'banana': 2}
fruit_counts = Counter(existing_counts)
print(fruit_counts)
# Output: Counter({'apple': 3, 'banana': 2})
 
# Depuis des arguments nommés
color_counts = Counter(red=5, blue=3, green=2)
print(color_counts)
# Output: Counter({'red': 5, 'blue': 3, 'green': 2})

Trouver les éléments les plus fréquents avec most_common()

Signature de méthode : most_common(n=None)

Paramètres :

  • n (optionnel) : nombre d’éléments les plus fréquents à renvoyer
  • Si n est omis ou vaut None, renvoie tous les éléments

Renvoie :

  • Une liste de tuples (item, count)
  • Triée par compte, du plus élevé au plus faible
  • Si les comptes sont égaux, les éléments sont dans l’ordre de première apparition
python
from collections import Counter
 
# Analyser la fréquence des mots dans un texte
text = "the quick brown fox jumps over the lazy dog the fox"
words = text.split()
word_counts = Counter(words)
 
# Obtenir les 3 mots les plus fréquents
top_3 = word_counts.most_common(3)
print(top_3)
# Output: [('the', 3), ('fox', 2), ('quick', 1)]

Opérations arithmétiques sur les Counters

Vous pouvez additionner, soustraire et effectuer d’autres opérations sur des objets Counter :

python
from collections import Counter
 
# Compter des éléments dans deux groupes
group1 = Counter(["apple", "banana", "apple", "orange"])
print(group1)
# Output: Counter({'apple': 2, 'banana': 1, 'orange': 1})
 
group2 = Counter(["banana", "banana", "grape", "apple"])
print(group2)
# Output: Counter({'banana': 2, 'grape': 1, 'apple': 1})
 
# Additionner les comptes
combined = group1 + group2
print(combined)
# Output: Counter({'apple': 3, 'banana': 3, 'orange': 1, 'grape': 1})
 
# Soustraire les comptes (ne conserve que les résultats positifs)
difference = group1 - group2
print(difference)
# Output: Counter({'apple': 1, 'orange': 1})
# banana: 1 - 2 = -1 (negative, so excluded)
# grape: not in group1, so excluded

Exemple pratique : analyser les notes des élèves

python
from collections import Counter
 
# Répartition des notes
grades = ["A", "B", "A", "C", "B", "A", "B", "D", "A", "B", "C", "A"]
grade_counts = Counter(grades)
 
print(f"Total students: {len(grades)}")
# Output: Total students: 12
 
print("\nGrade Distribution:")
for grade, count in grade_counts.most_common():
    percentage = (count / len(grades)) * 100
    bar = "█" * count
    print(f"  {grade}: {count} students ({percentage:4.1f}%) {bar}")
# Output:
# Grade Distribution:
#   A: 5 students (41.7%) █████
#   B: 4 students (33.3%) ████
#   C: 2 students (16.7%) ██
#   D: 1 students ( 8.3%) █

39.4.2) Dictionnaires avec valeurs par défaut avec defaultdict

La classe defaultdict est une sous-classe de dictionnaire (dict) qui crée automatiquement des entrées avec une valeur par défaut lorsque vous accédez à une clé manquante. Cela évite d’avoir à vérifier si les clés existent avant de les utiliser.

Ce que defaultdict accepte en entrée :

  • Une fonction default factory (obligatoire) : un appelable qui renvoie la valeur par défaut pour les clés manquantes
  • Tous les arguments qu’un dict classique accepte (paires clé-valeur, un autre dictionnaire, arguments nommés)

Avantage clé par rapport aux dictionnaires classiques :

  • Pas besoin de vérifier si une clé existe avant de l’utiliser
  • Initialise automatiquement les clés manquantes avec une valeur par défaut
  • Code plus propre et plus lisible pour les opérations de regroupement, comptage et accumulation

Comprendre la Default Factory

Quand vous créez un defaultdict, vous devez fournir une default factory — un appelable (fonction) qui ne prend aucun argument et renvoie la valeur par défaut. Default factories courantes :

  • int - renvoie 0 (utile pour le comptage)
  • list - renvoie [] (utile pour regrouper des éléments)
  • set - renvoie set() (utile pour collecter des éléments uniques)
  • str - renvoie '' (utile pour la concaténation de chaînes)
  • lambda: value - renvoie une valeur par défaut personnalisée
python
from collections import defaultdict
 
# Différentes default factories
counts = defaultdict(int)        # Les clés manquantes renvoient 0
groups = defaultdict(list)       # Les clés manquantes renvoient []
unique = defaultdict(set)        # Les clés manquantes renvoient set()
custom = defaultdict(lambda: "N/A")  # Les clés manquantes renvoient "N/A"
 
# Tester avec des clés manquantes
print(counts['missing'])     # Output: 0
print(groups['missing'])     # Output: []
print(unique['missing'])     # Output: set()
print(custom['missing'])     # Output: N/A

Utilisation de base : compter avec defaultdict

Comparez un dictionnaire classique vs defaultdict pour compter :

python
from collections import defaultdict
 
word = "mississippi"
 
# Dictionnaire classique - besoin de vérifier si la clé existe
regular_dict = {}
for letter in word:
    if letter not in regular_dict:
        regular_dict[letter] = 0
    regular_dict[letter] += 1
 
print(regular_dict)
# Output: {'m': 1, 'i': 4, 's': 4, 'p': 2}
 
# defaultdict - crée automatiquement des entrées avec une valeur par défaut
letter_counts = defaultdict(int)  # int() renvoie 0
for letter in word:
    letter_counts[letter] += 1  # Pas besoin de vérifier si la clé existe !
 
print(dict(letter_counts))
# Output: {'m': 1, 'i': 4, 's': 4, 'p': 2}

Comment ça fonctionne :

  1. Quand vous accédez à letter_counts[letter] pour une nouvelle lettre, defaultdict appelle int() qui renvoie 0
  2. La clé est créée avec la valeur 0, puis += 1 la fait passer à 1
  3. Pour les clés existantes, il se comporte comme un dictionnaire normal

Regrouper des éléments avec defaultdict(list)

Un cas d’usage courant est le regroupement d’éléments par catégories :

python
from collections import defaultdict
 
students = [
    ("Alice", "A"),
    ("Bob", "B"),
    ("Charlie", "A"),
    ("Diana", "C"),
    ("Eve", "B"),
    ("Frank", "A")
]
 
# Regrouper les élèves par note
# Avec defaultdict - propre et simple
students_by_grade = defaultdict(list)
for name, grade in students:
    students_by_grade[grade].append(name)
 
print(dict(students_by_grade))
# Output: {'A': ['Alice', 'Charlie', 'Frank'], 'B': ['Bob', 'Eve'], 'C': ['Diana']}
 
# Accéder à une note qui n’existe pas encore
print(students_by_grade["D"])  # Output: [] (empty list, not KeyError!)

Comment ça fonctionne :

  1. Quand vous accédez à students_by_grade[grade] pour une nouvelle note, defaultdict appelle list() qui renvoie []
  2. La clé est créée avec une liste vide, puis .append(name) ajoute le premier élève
  3. Pour les notes existantes, il ajoute simplement à la liste existante

Créer un defaultdict à partir d’un dictionnaire existant

Vous pouvez initialiser un defaultdict avec des données existantes :

python
from collections import defaultdict
 
# Démarrer avec des comptes existants
existing_data = {'apple': 5, 'banana': 3}
 
# Créer un defaultdict à partir d’un dictionnaire existant
fruit_counts = defaultdict(int, existing_data)
 
# Ajouter d’autres comptes
fruit_counts['apple'] += 2     # 5 + 2 = 7
fruit_counts['orange'] += 1    # 0 + 1 = 1 (new key, starts at 0)
 
print(dict(fruit_counts))
# Output: {'apple': 7, 'banana': 3, 'orange': 1}

Default factory personnalisée

Vous pouvez fournir n’importe quel appelable comme default factory :

python
from collections import defaultdict
 
# Utiliser lambda pour des valeurs par défaut personnalisées
page_views = defaultdict(lambda: {'views': 0, 'unique': 0})
 
page_views['home']['views'] = 100
page_views['home']['unique'] = 75
 
print(page_views['home'])
# Output: {'views': 100, 'unique': 75}
 
print(page_views['about'])  # New key gets default dictionary
# Output: {'views': 0, 'unique': 0}

Remarques importantes

Accéder vs. vérifier les clés :

python
from collections import defaultdict
 
counts = defaultdict(int)
 
# Accéder à une clé manquante la CRÉE
value = counts['missing']  # Crée 'missing' avec la valeur 0
print('missing' in counts)  # Output: True
 
# Pour vérifier sans créer, utilisez 'in' ou .get()
counts2 = defaultdict(int)
print('missing' in counts2)      # Output: False (doesn't create key)
print(counts2.get('missing'))    # Output: None (doesn't create key)

39.5) (Optionnel) Outils d’itération utiles

Le module itertools fournit des fonctions pour créer des itérateurs efficaces. Ces outils vous aident à travailler avec des séquences de manière puissante sans créer de grandes listes (list) intermédiaires.

39.5.1) Chaîner des itérables avec chain()

La fonction chain() combine plusieurs itérables en un seul itérateur qui produit les éléments de chaque itérable dans l’ordre.

Ce que chain() accepte :

  • Plusieurs itérables (listes (list), tuples, chaînes, etc.) comme arguments séparés

Ce que chain() renvoie :

  • Un itérateur qui produit tous les éléments du premier itérable, puis tous les éléments du second, et ainsi de suite

Avantage clé :

  • Plus économe en mémoire que la concaténation avec + (ne crée pas de listes intermédiaires)
  • Fonctionne avec n’importe quel itérable, pas seulement les listes
python
from itertools import chain
 
# Combiner plusieurs listes
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9]
 
combined = chain(list1, list2, list3)
print(list(combined))  # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]

C’est plus économe en mémoire que de concaténer des listes avec +, surtout pour de grandes séquences :

python
from itertools import chain
 
# Traiter plusieurs sources de données sans créer une grande liste combinée
students_class_a = ["Alice", "Bob", "Charlie"]
students_class_b = ["Diana", "Eve", "Frank"]
students_class_c = ["Grace", "Henry", "Iris"]
 
# Itérer sur tous les élèves sans créer une liste combinée
for student in chain(students_class_a, students_class_b, students_class_c):
    print(f"Processing: {student}")
# Output:
# Processing: Alice
# Processing: Bob
# Processing: Charlie
# Processing: Diana
# Processing: Eve
# Processing: Frank
# Processing: Grace
# Processing: Henry
# Processing: Iris

Vous pouvez chaîner différents types d’itérables :

python
from itertools import chain
 
# Chaîner des listes, tuples et chaînes
numbers = [1, 2, 3]
letters = ("a", "b", "c")
word = "xyz"
 
combined = chain(numbers, letters, word)
print(list(combined))  # Output: [1, 2, 3, 'a', 'b', 'c', 'x', 'y', 'z']

39.5.2) Répéter des éléments avec cycle()

La fonction cycle() crée un itérateur infini qui parcourt en boucle les éléments d’un itérable.

Ce que cycle() accepte :

  • Un seul itérable (liste (list), tuple, chaîne, etc.)

Ce que cycle() renvoie :

  • Un itérateur infini qui produit les éléments de l’itérable de manière répétée
  • Après avoir atteint la fin, il recommence au début

Caractéristiques clés :

  • Crée un itérateur infini — ne s’arrête jamais de lui-même
  • Doit être utilisé avec une condition d’arrêt (compteur, break, ou zip())
  • Économe en mémoire : ne crée pas de copies des données
python
from itertools import cycle
 
# Créer un cycle infini de couleurs
colors = cycle(["red", "green", "blue"])
 
# Prendre les 10 premières couleurs
for i, color in enumerate(colors):
    if i >= 10:
        break
    print(f"Item {i}: {color}")
# Output:
# Item 0: red
# Item 1: green
# Item 2: blue
# Item 3: red
# Item 4: green
# Item 5: blue
# Item 6: red
# Item 7: green
# Item 8: blue
# Item 9: red

Avertissement : cycle() crée un itérateur infini. Utilisez-le toujours avec une condition d’arrêt (comme un compteur ou une instruction break), sinon vous créerez une boucle infinie.

Un cas d’usage pratique consiste à alterner entre des valeurs :

python
from itertools import cycle
 
# Alterner entre deux couleurs de fond pour les lignes d’un tableau
row_colors = cycle(["white", "lightgray"])
 
rows = ["Row 1", "Row 2", "Row 3", "Row 4", "Row 5"]
for row, color in zip(rows, row_colors):
    print(f"{row}: background-color: {color}")
# Output:
# Row 1: background-color: white
# Row 2: background-color: lightgray
# Row 3: background-color: white
# Row 4: background-color: lightgray
# Row 5: background-color: white

Ici, nous utilisons zip() (que nous avons appris au chapitre 37) pour associer chaque ligne à une couleur. L’itérateur cycle() répète automatiquement les couleurs selon les besoins.

39.5.3) Combiner chain() et cycle()

Vous pouvez combiner des fonctions itertools pour des motifs plus complexes :

python
from itertools import chain, cycle
 
# Créer un motif qui alterne entre plusieurs séquences
pattern1 = [1, 2, 3]
pattern2 = [10, 20]
 
# Chaîner les motifs, puis faire un cycle sur le résultat
combined_pattern = cycle(chain(pattern1, pattern2))
 
# Prendre les 12 premières valeurs
for i, value in enumerate(combined_pattern):
    if i >= 12:
        break
    print(value, end=" ")
# Output: 1 2 3 10 20 1 2 3 10 20 1 2
 
print()  # Newline

Cela crée un motif répétitif : 1, 2, 3, 10, 20, 1, 2, 3, 10, 20, ...

Voici un exemple pratique de création d’un planning tournant :

python
from itertools import cycle
 
# Créer un planning tournant pour les membres de l’équipe
team_members = ["Alice", "Bob", "Charlie"]
schedule = cycle(team_members)
 
# Assigner des tâches aux membres de l’équipe à tour de rôle
tasks = [
    "Review code",
    "Write tests",
    "Update documentation",
    "Fix bug #123",
    "Implement feature X",
    "Deploy to staging"
]
 
print("Task Assignments:")
for task, assignee in zip(tasks, schedule):
    print(f"  {assignee}: {task}")
# Output:
# Task Assignments:
#   Alice: Review code
#   Bob: Write tests
#   Charlie: Update documentation
#   Alice: Fix bug #123
#   Bob: Implement feature X
#   Charlie: Deploy to staging

Module itertools

chain : Combiner des itérables

cycle : Répéter indéfiniment

Plus économe en mémoire que +

Fonctionne avec différents types

Crée un itérateur infini

Toujours utiliser avec une condition d’arrêt

Utile pour alterner des motifs


Dans ce chapitre, nous avons exploré cinq modules essentiels de la bibliothèque standard qui étendent les capacités de Python :

  • random : générer des nombres aléatoires, effectuer des sélections aléatoires et mélanger des séquences — essentiel pour les simulations, les jeux et les tests
  • datetime : travailler avec des dates, des heures et des durées — calculer des âges, planifier des événements et formater des horodatages
  • json : échanger des données avec d’autres programmes en utilisant le format JSON universel — sauvegarder l’état d’une application, travailler avec des API web et stocker une configuration
  • collections : utiliser des conteneurs spécialisés comme Counter pour compter et defaultdict pour créer automatiquement des clés
  • itertools : créer des itérateurs efficaces avec chain() pour combiner des séquences et cycle() pour répéter des motifs

Ces modules font partie de la bibliothèque standard de Python — ils sont toujours disponibles, bien testés, et résolvent élégamment des problèmes de programmation courants. À mesure que vous construisez des programmes plus complexes, vous vous surprendrez à utiliser ces outils fréquemment. Ils représentent la philosophie de Python du « batteries included » — fournir des solutions puissantes, prêtes à l’emploi, pour les tâches de programmation du quotidien.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai