# 520 Exercices Python Complets - De Débutant à Expert

Guide d'utilisation :

- Chaque chapitre contient 10 exercices progressifs
- Les exercices explorent toutes les fonctionnalités du sujet traité
- Faites les exercices dans l'ordre pour une progression optimale
- N'hésitez pas à tester et modifier votre code

## [LIGHT_BLUE_HEART] PARTIE 1 — Les Fondamentaux (Débutant total)

---

### **Chapitre 1 — Introduction à Python**

**Exercice 1.1** - Premier contact  
Écris un programme qui affiche "Bienvenue dans le monde de Python !" à l'écran. Utilise la fonction `print()`.

**Exercice 1.2** - Affichage multiple  
Crée un programme qui affiche 5 lignes différentes : ton prénom, ton âge, ta ville, ton pays et ta couleur préférée. Chaque information sur une ligne séparée.

**Exercice 1.3** - Commentaires  
Écris un programme qui affiche "Python est génial" et ajoute au moins 3 commentaires dans ton code pour expliquer ce que tu fais. Utilise `#` pour les commentaires.

**Exercice 1.4** - Affichage avec séparateurs  
Utilise `print()` pour afficher plusieurs mots sur la même ligne, séparés par des tirets. Exemple : "Python-est-facile". Explore le paramètre `sep=` de print.

**Exercice 1.5** - Affichage sans saut de ligne  
Écris trois instructions `print()` qui affichent "Je", "code", "Python" sur la même ligne avec des espaces. Utilise le paramètre `end=` de print.

**Exercice 1.6** - Calculs simples avec print  
Affiche directement le résultat de 15 + 27, 100 - 35, 12 * 8 et 144 / 12 avec `print()`. Affiche aussi le texte expliquant chaque opération.

**Exercice 1.7** - Caractères spéciaux  
Crée un programme qui affiche : une citation entre guillemets, un texte avec un retour à la ligne `\n`, et un texte avec une tabulation `\t`.

**Exercice 1.8** - Répétition avec print  
Utilise `print()` pour afficher 10 fois le symbole "\*" sur la même ligne, puis affiche "Python" répété 5 fois verticalement (une ligne par mot).

**Exercice 1.9** - Affichage formaté simple  
Affiche un rectangle avec des caractères. Exemple :

```
****
*  *
****
```

**Exercice 1.10** - Programme interactif basique  
Écris un programme qui affiche "Appuie sur Entrée pour continuer...", attend que l'utilisateur appuie sur Entrée (utilise `input()`), puis affiche "Programme terminé !".

---

### **Chapitre 2 — Variables, types et opérations**

**Exercice 2.1** - Création de variables  
Crée 5 variables : `nom` (texte), `age` (nombre entier), `taille` (nombre décimal), `est_etudiant` (booléen), et `ville` (texte). Affiche chaque variable avec son type en utilisant `type()`.

**Exercice 2.2** - Opérations arithmétiques  
Crée deux variables `a = 45` et `b = 12`. Calcule et affiche : leur somme, différence, produit, division, division entière `//`, modulo `%`, et `a` à la puissance `b` (utilise `**`).

**Exercice 2.3** - Conversion de types  
Crée une variable `nombre_texte = "123"`. Convertis-la en entier, puis en flottant. Crée une variable `prix = 45.99` et convertis-la en entier. Affiche tous les résultats et leurs types.

**Exercice 2.4** - Calcul de moyenne  
Demande à l'utilisateur d'entrer 3 notes (utilise `input()` et convertis en float). Calcule et affiche la moyenne de ces trois notes avec 2 décimales.

**Exercice 2.5** - Opérations sur variables  
Crée une variable `compteur = 0`. Incrémente-la de 5, multiplie-la par 3, soustrais 10, divise par 2. Affiche la valeur à chaque étape avec un message explicatif.

**Exercice 2.6** - Calculs avec modulo  
Demande un nombre à l'utilisateur. Affiche si ce nombre est pair ou impair en utilisant l'opérateur `%`. Affiche aussi le reste de sa division par 3 et par 5.

**Exercice 2.7** - Types booléens  
Crée des variables booléennes : `est_majeur = True`, `a_permis = False`. Teste et affiche le résultat de : `est_majeur and a_permis`, `est_majeur or a_permis`, `not est_majeur`.

**Exercice 2.8** - Comparaisons  
Crée deux variables `x = 25` et `y = 30`. Teste et affiche le résultat de toutes les comparaisons : `==`, `!=`, `<`, `>`, `<=`, `>=` entre x et y.

**Exercice 2.9** - Calcul d'aire  
Demande à l'utilisateur la longueur et la largeur d'un rectangle. Calcule et affiche le périmètre et l'aire. Fais de même pour un cercle (demande le rayon, utilise 3.14159 pour π).

**Exercice 2.10** - Conversion température  
Demande une température en Celsius. Convertis-la en Fahrenheit (formule : F = C \* 9/5 + 32) et en Kelvin (formule : K = C + 273.15). Affiche les trois valeurs avec des messages clairs.

---

### **Chapitre 3 — Chaînes de caractères (string)**

**Exercice 3.1** - Manipulation basique  
Crée une variable `phrase = "python est génial"`. Affiche cette phrase en majuscules avec `.upper()`, en minuscules avec `.lower()`, et avec la première lettre en majuscule avec `.capitalize()`.

**Exercice 3.2** - Indexation  
Crée `mot = "Programmation"`. Affiche le premier caractère `[0]`, le dernier `[-1]`, le 5ème caractère, et vérifie la longueur totale avec `len()`.

**Exercice 3.3** - Slicing  
Avec `texte = "Apprendre Python est amusant"`, extrais et affiche : les 9 premiers caractères, les 6 derniers, du caractère 10 à 16, tous les caractères avec un pas de 2, et la phrase inversée avec `[::-1]`.

**Exercice 3.4** - Méthodes de recherche  
Crée `phrase = "Je code en Python et j'adore Python"`. Utilise `.find()` pour trouver la position de "Python", `.count()` pour compter combien de fois "Python" apparaît, et `.index()` pour localiser "code".

**Exercice 3.5** - Split et Join  
Crée `phrase = "rouge,vert,bleu,jaune"`. Utilise `.split(',')` pour séparer en liste. Puis utilise `.join()` pour reformer une chaîne avec " - " comme séparateur. Affiche les résultats.

**Exercice 3.6** - Remplacement  
Crée `texte = "J'aime les bananes et les bananes sont délicieuses"`. Remplace "bananes" par "pommes" avec `.replace()`. Essaie aussi de remplacer seulement la première occurrence avec le paramètre count.

**Exercice 3.7** - Tests de chaînes  
Crée plusieurs chaînes et teste avec : `.isalpha()` (que des lettres), `.isdigit()` (que des chiffres), `.isalnum()` (lettres et chiffres), `.islower()`, `.isupper()`, `.isspace()`. Affiche les résultats.

**Exercice 3.8** - Suppression d'espaces  
Crée `texte = "   Python   "`. Utilise `.strip()` pour enlever les espaces au début et à la fin, `.lstrip()` pour seulement à gauche, `.rstrip()` pour seulement à droite. Affiche et compare.

**Exercice 3.9** - F-strings  
Crée des variables `nom = "Marie"`, `age = 25`, `ville = "Paris"`. Utilise les f-strings pour créer et afficher une phrase : "Je m'appelle Marie, j'ai 25 ans et j'habite à Paris". Ajoute des calculs dans les f-strings (exemple : `f"Dans 5 ans, j'aurai {age + 5} ans"`).

**Exercice 3.10** - Formatage avancé  
Crée `prix = 19.5`. Affiche ce prix avec : 2 décimales avec `:.2f`, 5 caractères de large avec alignement à droite `:>5`, et avec alignement à gauche `:<5`. Crée aussi une chaîne `nom = "Ali"` et affiche-la sur 10 caractères avec centrage `:^10`.

---

### **Chapitre 4 — Listes, tuples et sets**

**Exercice 4.1** - Création et accès aux listes  
Crée une liste `fruits = ["pomme", "banane", "orange", "kiwi", "mangue"]`. Affiche : le 1er fruit, le dernier, les 3 premiers avec slicing, et la longueur de la liste avec `len()`.

**Exercice 4.2** - Modification de listes  
Crée `nombres = [10, 20, 30, 40, 50]`. Modifie le 2ème élément en 25, ajoute 60 à la fin avec `.append()`, insère 15 à la position 1 avec `.insert()`, et supprime 30 avec `.remove()`. Affiche la liste après chaque opération.

**Exercice 4.3** - Méthodes de listes  
Crée `liste = [3, 1, 4, 1, 5, 9, 2, 6]`. Utilise : `.sort()` pour trier, `.reverse()` pour inverser, `.count(1)` pour compter les 1, `.index(5)` pour trouver la position de 5, `.clear()` pour vider. Affiche après chaque étape.

**Exercice 4.4** - Extend et concaténation  
Crée deux listes `liste1 = [1, 2, 3]` et `liste2 = [4, 5, 6]`. Combine-les avec `.extend()`, puis essaie avec `+`, et avec `*` pour répéter une liste. Utilise aussi `.copy()` pour créer une copie indépendante.

**Exercice 4.5** - Pop et del  
Crée `animaux = ["chat", "chien", "oiseau", "poisson", "lapin"]`. Supprime le dernier avec `.pop()`, supprime à l'index 2 avec `.pop(2)`, supprime l'élément à l'index 0 avec `del`, et supprime toute la liste entre index 1 et 3 avec slicing `del`.

**Exercice 4.6** - Tuples  
Crée un tuple `coordonnees = (10, 20, 30)`. Accède aux éléments par index. Essaie de modifier un élément (ça doit générer une erreur). Crée un tuple avec un seul élément `tuple1 = (5,)`. Concatène deux tuples et affiche la longueur.

**Exercice 4.7** - Unpacking  
Crée `point = (100, 200)`. Décompose en variables `x, y = point`. Crée une liste `valeurs = [1, 2, 3, 4, 5]` et décompose : `premier, *milieu, dernier = valeurs`. Affiche toutes les variables créées.

**Exercice 4.8** - Sets (ensembles)  
Crée deux sets : `set1 = {1, 2, 3, 4, 5}` et `set2 = {4, 5, 6, 7, 8}`. Calcule et affiche : l'union avec `|`, l'intersection avec `&`, la différence avec `-`, la différence symétrique avec `^`. Ajoute un élément avec `.add()` et supprime avec `.remove()`.

**Exercice 4.9** - Conversion entre types  
Crée une liste `liste = [1, 2, 2, 3, 3, 3, 4]`. Convertis-la en set pour enlever les doublons, puis reconvertis en liste. Convertis en tuple. Crée un tuple et convertis-le en liste pour le modifier, puis reconvertis en tuple.

**Exercice 4.10** - Listes de listes (matrices)  
Crée une matrice 3x3 : `matrice = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]`. Accède à l'élément au centre (5), modifie l'élément en position [0][0], affiche la première ligne, affiche la dernière colonne élément par élément.

---

### **Chapitre 5 — Dictionnaires (dict)**

**Exercice 5.1** - Création et accès  
Crée un dictionnaire `personne = {"nom": "Ahmed", "age": 28, "ville": "Dakar", "profession": "Ingénieur"}`. Accède et affiche chaque valeur par sa clé. Affiche aussi toutes les clés avec `.keys()` et toutes les valeurs avec `.values()`.

**Exercice 5.2** - Modification et ajout  
Crée `produit = {"nom": "Laptop", "prix": 800, "stock": 15}`. Modifie le prix à 750, ajoute une clé "marque" avec la valeur "Dell", incrémente le stock de 5. Affiche le dictionnaire après chaque modification.

**Exercice 5.3** - Méthodes get et setdefault  
Crée `scores = {"Alice": 95, "Bob": 87}`. Utilise `.get("Alice")` pour obtenir le score, puis `.get("Charlie", 0)` pour un nom inexistant (valeur par défaut 0). Utilise `.setdefault("David", 75)` pour ajouter David s'il n'existe pas.

**Exercice 5.4** - Suppression d'éléments  
Crée `donnees = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}`. Supprime la clé "c" avec `del`, supprime "d" avec `.pop()`, supprime le dernier élément ajouté avec `.popitem()`, efface tout avec `.clear()`. Affiche après chaque étape.

**Exercice 5.5** - Parcours de dictionnaires  
Crée `notes = {"Math": 15, "Français": 14, "Anglais": 16, "Sciences": 13}`. Parcours et affiche : toutes les clés, toutes les valeurs, tous les couples clé-valeur avec `.items()`. Calcule aussi la moyenne des notes.

**Exercice 5.6** - Update et merge  
Crée `dict1 = {"a": 1, "b": 2}` et `dict2 = {"b": 3, "c": 4}`. Fusionne dict2 dans dict1 avec `.update()`. Essaie aussi la fusion avec l'opérateur `|` (Python 3.9+). Crée une copie avec `.copy()`.

**Exercice 5.7** - Dictionnaires imbriqués  
Crée un dictionnaire d'étudiants :

```python
etudiants = {
    "Alice": {"age": 20, "notes": [15, 16, 14]},
    "Bob": {"age": 22, "notes": [12, 13, 15]}
}
```

Accède à l'âge d'Alice, à la première note de Bob, modifie l'âge d'Alice, ajoute une note à Bob.

**Exercice 5.8** - Compréhension de dictionnaire  
Crée un dictionnaire `nombres = {"un": 1, "deux": 2, "trois": 3}`. Crée un nouveau dictionnaire avec les valeurs doublées en utilisant une compréhension : `{k: v*2 for k, v in nombres.items()}`. Fais de même pour filtrer les valeurs > 1.

**Exercice 5.9** - Fromkeys et opérations  
Utilise `.fromkeys()` pour créer un dictionnaire avec les clés ["nom", "age", "ville"] toutes initialisées à None. Teste l'opérateur `in` pour vérifier si une clé existe. Affiche la longueur du dictionnaire avec `len()`.

**Exercice 5.10** - Compteur avec dictionnaires  
Crée une chaîne `texte = "abracadabra"`. Crée un dictionnaire qui compte le nombre d'occurrences de chaque lettre. Parcours la chaîne caractère par caractère et incrémente le compteur dans le dictionnaire.

---

### **Chapitre 6 — Conditions et boucles**

**Exercice 6.1** - If simple  
Demande l'âge de l'utilisateur. Si l'âge est >= 18, affiche "Vous êtes majeur", sinon affiche "Vous êtes mineur". Teste avec différentes valeurs.

**Exercice 6.2** - If elif else  
Demande une note entre 0 et 20. Affiche la mention : "Excellent" (>= 16), "Bien" (>= 14), "Assez bien" (>= 12), "Passable" (>= 10), "Insuffisant" (< 10).

**Exercice 6.3** - Conditions multiples  
Demande le prix d'un produit et si l'utilisateur a une carte de fidélité (oui/non). Si prix > 100 ET carte fidélité, réduction de 20%. Si prix > 100 OU carte fidélité, réduction de 10%. Sinon pas de réduction. Affiche le prix final.

**Exercice 6.4** - Boucle for avec range  
Affiche les nombres de 1 à 10 avec une boucle for. Puis affiche les nombres pairs de 0 à 20. Affiche les nombres de 10 à 1 en ordre décroissant. Affiche les multiples de 5 entre 0 et 50.

**Exercice 6.5** - Boucle for sur listes  
Crée `fruits = ["pomme", "banane", "orange", "kiwi"]`. Parcours la liste et affiche chaque fruit. Utilise `enumerate()` pour afficher aussi l'index de chaque fruit.

**Exercice 6.6** - Boucle while  
Crée un compteur initialisé à 0. Avec une boucle while, incrémente-le et affiche-le jusqu'à ce qu'il atteigne 10. Crée aussi un programme qui demande à l'utilisateur d'entrer "stop" pour arrêter la boucle.

**Exercice 6.7** - Break et continue  
Affiche les nombres de 1 à 20, mais saute (continue) les multiples de 3 et arrête (break) à 15. Crée aussi une boucle qui cherche un nombre dans une liste et s'arrête quand elle le trouve.

**Exercice 6.8** - Boucles imbriquées  
Crée un programme avec deux boucles for imbriquées qui affiche une table de multiplication (de 1 à 10). Format : "3 x 4 = 12".

**Exercice 6.9** - For avec dictionnaires  
Crée `scores = {"Alice": 95, "Bob": 87, "Charlie": 92}`. Parcours le dictionnaire et affiche chaque nom avec son score. Trouve et affiche aussi le nom de la personne avec le meilleur score.

**Exercice 6.10** - Validation avec boucle  
Crée un programme qui demande à l'utilisateur d'entrer un nombre entre 1 et 100. Tant que le nombre n'est pas dans cette plage, redemande. Affiche "Bravo !" quand le nombre est valide.

---

### **Chapitre 7 — Fonctions et portée**

**Exercice 7.1** - Fonction simple  
Crée une fonction `dire_bonjour()` qui affiche "Bonjour !". Appelle cette fonction 3 fois. Crée une fonction `dire_bonjour_nom(nom)` qui affiche "Bonjour [nom] !".

**Exercice 7.2** - Fonctions avec return  
Crée une fonction `addition(a, b)` qui retourne la somme de a et b. Crée aussi `multiplication(a, b)`, `soustraction(a, b)`, `division(a, b)`. Teste toutes ces fonctions.

**Exercice 7.3** - Valeurs par défaut  
Crée une fonction `presenter(nom, age=18, ville="Dakar")` avec des valeurs par défaut. Appelle-la de différentes façons : sans arguments optionnels, avec juste age, avec age et ville.

**Exercice 7.4** - Return multiple  
Crée une fonction `calculer_rectangle(longueur, largeur)` qui retourne à la fois le périmètre ET l'aire. Récupère les deux valeurs dans des variables séparées lors de l'appel.

**Exercice 7.5** - Args et kwargs  
Crée une fonction `somme(*args)` qui accepte un nombre variable d'arguments et retourne leur somme. Crée une fonction `afficher_infos(**kwargs)` qui affiche toutes les paires clé-valeur reçues.

**Exercice 7.6** - Fonctions imbriquées  
Crée une fonction `calculer(x, y, operation)` où operation est une chaîne ("add", "sub", "mul", "div"). À l'intérieur, définis 4 fonctions imbriquées pour chaque opération et appelle la bonne selon le paramètre.

**Exercice 7.7** - Portée (scope)  
Crée une variable globale `compteur = 0`. Crée une fonction qui incrémente cette variable (utilise `global`). Crée une autre fonction avec une variable locale du même nom. Affiche les différences.

**Exercice 7.8** - Docstrings  
Crée une fonction `calculer_moyenne(liste_nombres)` avec une docstring complète expliquant ce qu'elle fait, ses paramètres et ce qu'elle retourne. Affiche la docstring avec `help()` ou `__doc__`.

**Exercice 7.9** - Fonction récursive  
Crée une fonction récursive `factorielle(n)` qui calcule n! (n factorielle). Par exemple : 5! = 5 × 4 × 3 × 2 × 1 = 120. Teste avec différentes valeurs.

**Exercice 7.10** - Mini calculatrice  
Crée un programme avec un menu qui propose : 1-Addition, 2-Soustraction, 3-Multiplication, 4-Division, 5-Quitter. Chaque opération est une fonction. L'utilisateur choisit l'opération et entre deux nombres.

---

## [IDEE] PARTIE 2 — Structurer son code comme un pro

---

### **Chapitre 8 — Modules et packages**

**Exercice 8.1** - Import de modules standard  
Importe le module `math`. Utilise `math.sqrt()` pour calculer la racine carrée de 144, `math.pi` pour afficher π, `math.pow(2, 10)` pour 2^10, `math.ceil()` et `math.floor()` pour arrondir 7.8.

**Exercice 8.2** - Module random  
Importe `random`. Génère un nombre aléatoire entre 1 et 100 avec `random.randint()`, un nombre flottant entre 0 et 1 avec `random.random()`, choisis un élément aléatoire dans une liste avec `random.choice()`, mélange une liste avec `random.shuffle()`.

**Exercice 8.3** - Module datetime  
Importe `datetime`. Affiche la date et l'heure actuelle, affiche seulement la date du jour, calcule la date dans 30 jours, calcule combien de jours se sont écoulés depuis le 1er janvier 2024.

**Exercice 8.4** - Création de module simple  
Crée un fichier `operations.py` avec 4 fonctions : addition, soustraction, multiplication, division. Dans un autre fichier, importe ce module et utilise toutes les fonctions.

**Exercice 8.5** - Import sélectif  
Crée un module `geometrie.py` avec des fonctions : `aire_carre`, `aire_rectangle`, `aire_cercle`, `aire_triangle`. Importe seulement `aire_carre` et `aire_cercle` avec `from geometrie import aire_carre, aire_cercle`.

**Exercice 8.6** - Alias d'import  
Importe `datetime` avec l'alias `dt`, `math` avec l'alias `m`. Utilise ces alias pour faire des calculs : `dt.datetime.now()`, `m.sqrt(64)`.

**Exercice 8.7** - Module sys  
Importe `sys`. Affiche la version de Python avec `sys.version`, le chemin d'exécution avec `sys.executable`, les arguments de ligne de commande avec `sys.argv`, quitte le programme avec `sys.exit()`.

**Exercice 8.8** - Module os  
Importe `os`. Affiche le répertoire de travail actuel avec `os.getcwd()`, liste les fichiers du répertoire avec `os.listdir()`, crée un nouveau dossier avec `os.mkdir()`, vérifie si un fichier existe avec `os.path.exists()`.

**Exercice 8.9** - Package structure  
Crée un package (dossier) nommé `calculatrice` avec un fichier `__init__.py` vide. À l'intérieur, crée deux modules : `basique.py` (addition, soustraction) et `avance.py` (puissance, racine). Importe et utilise depuis un autre fichier.

**Exercice 8.10** - Module if **name**  
Crée un module avec plusieurs fonctions. Ajoute un bloc `if __name__ == "__main__":` pour tester les fonctions quand le module est exécuté directement, mais pas quand il est importé.

---

### **Chapitre 9 — Gestion des erreurs et exceptions**

**Exercice 9.1** - Try except simple  
Demande deux nombres à l'utilisateur et divise-les. Utilise try-except pour capturer l'erreur `ZeroDivisionError` si l'utilisateur entre 0 comme diviseur. Affiche un message d'erreur approprié.

**Exercice 9.2** - Multiple exceptions  
Crée un programme qui demande un index et une liste. Accède à l'élément à cet index. Capture `ValueError` (si l'index n'est pas un nombre) et `IndexError` (si l'index est hors limites).

**Exercice 9.3** - Try except else finally  
Demande un nombre à l'utilisateur. Dans try : convertis en int. Dans except : capture ValueError. Dans else : affiche "Conversion réussie". Dans finally : affiche "Opération terminée".

**Exercice 9.4** - Levée d'exception  
Crée une fonction `verifier_age(age)` qui lève une `ValueError` si l'âge est négatif ou > 150 avec `raise ValueError("Âge invalide")`. Appelle cette fonction et capture l'exception.

**Exercice 9.5** - Exception personnalisée  
Crée une classe d'exception personnalisée `MonteeTropBasseError(Exception)`. Crée une fonction `verifier_temperature(temp)` qui lève cette exception si temp < -273.15 (zéro absolu). Teste.

**Exercice 9.6** - Gestion de fichiers avec exceptions  
Essaie d'ouvrir un fichier inexistant. Capture `FileNotFoundError`. Essaie de lire un fichier. Capture `PermissionError` si tu n'as pas les droits. Utilise finally pour afficher "Tentative terminée".

**Exercice 9.7** - Exceptions multiples types  
Crée un programme de calculatrice. Capture : `ValueError` (entrée non numérique), `ZeroDivisionError` (division par zéro), et une exception générique `Exception` pour toute autre erreur.

**Exercice 9.8** - Assert  
Utilise `assert` pour vérifier des conditions. Crée une fonction `diviser(a, b)` avec `assert b != 0, "Le diviseur ne peut pas être zéro"`. Teste avec b=0 pour voir l'AssertionError.

**Exercice 9.9** - Logging d'erreurs  
Crée un programme qui effectue plusieurs opérations risquées (conversion, division, accès liste). Pour chaque erreur capturée, affiche un message détaillé avec le type d'erreur et une description.

**Exercice 9.10** - Programme robuste  
Crée un programme complet de gestion de notes d'étudiants. Gère toutes les erreurs possibles : entrées invalides, divisions par zéro pour la moyenne, accès à des index inexistants. Le programme ne doit jamais crasher.

---

### **Chapitre 10 — Entrée / sortie et fichiers**

**Exercice 10.1** - Lecture de fichier  
Crée un fichier texte `notes.txt` avec quelques lignes. Écris un programme qui ouvre ce fichier avec `open()` en mode lecture 'r', lit tout le contenu avec `.read()`, et l'affiche. N'oublie pas `.close()`.

**Exercice 10.2** - Écriture de fichier  
Crée un programme qui demande à l'utilisateur son nom et son âge. Écris ces informations dans un fichier `info_utilisateur.txt` avec `open()` en mode écriture 'w'. Ferme le fichier. Ouvre à nouveau et affiche le contenu.

**Exercice 10.3** - Ajout à un fichier  
Crée un fichier `journal.txt`. Écris un programme qui demande à l'utilisateur d'entrer une ligne de journal. Ajoute cette ligne au fichier en mode 'a' (append) sans écraser le contenu existant. Teste en ajoutant plusieurs lignes.

**Exercice 10.4** - Context manager (with)  
Réécris l'exercice 10.1 en utilisant `with open() as f:` pour ouvrir le fichier. Compare avec la version sans with. Utilise `.readlines()` pour lire ligne par ligne et affiche chaque ligne avec son numéro.

**Exercice 10.5** - Lecture ligne par ligne  
Crée un fichier avec une liste de courses (un article par ligne). Écris un programme qui lit le fichier ligne par ligne dans une boucle, compte le nombre total d'articles, et affiche chaque article numéroté.

**Exercice 10.6** - Fichiers CSV  
Crée un fichier CSV `etudiants.csv` avec des colonnes : nom, prénom, note. Écris un programme qui lit ce fichier, sépare chaque ligne par les virgules avec `.split(',')`, et affiche les données sous forme de tableau.

**Exercice 10.7** - Module CSV  
Importe le module `csv`. Crée un programme qui écrit des données d'étudiants dans un fichier CSV en utilisant `csv.writer()`. Puis lis ce fichier avec `csv.reader()` et affiche chaque ligne.

**Exercice 10.8** - Fichiers JSON  
Importe `json`. Crée un dictionnaire avec des informations sur une personne. Sauvegarde ce dictionnaire dans un fichier JSON avec `json.dump()`. Relis le fichier avec `json.load()` et affiche les données.

**Exercice 10.9** - Gestion d'erreurs fichiers  
Crée un programme qui demande un nom de fichier à l'utilisateur. Essaie de l'ouvrir et de le lire. Gère les exceptions : fichier inexistant (`FileNotFoundError`), pas de permissions (`PermissionError`).

**Exercice 10.10** - Traitement de fichier complet  
Crée un fichier texte avec plusieurs phrases. Écris un programme qui : lit le fichier, compte le nombre de lignes, de mots (avec `.split()`), de caractères, trouve le mot le plus long, et écrit ces statistiques dans un nouveau fichier `statistiques.txt`.

---

### **Chapitre 11 — Les compréhensions**

**Exercice 11.1** - Liste comprehension basique  
Crée une liste des carrés des nombres de 1 à 10 avec une compréhension : `[x**2 for x in range(1, 11)]`. Compare avec une boucle for classique.

**Exercice 11.2** - Compréhension avec condition  
Crée une liste des nombres pairs entre 1 et 20 avec compréhension : `[x for x in range(1, 21) if x % 2 == 0]`. Crée aussi une liste des multiples de 3 et 5.

**Exercice 11.3** - Compréhension sur chaînes  
Crée une liste de mots : `mots = ["Python", "Java", "C++", "Ruby"]`. Crée une nouvelle liste avec tous les mots en majuscules. Crée une liste avec seulement les mots de plus de 4 lettres.

**Exercice 11.4** - If-else dans compréhension  
Crée une liste avec les nombres de 1 à 10. Avec une compréhension, crée une nouvelle liste qui contient "pair" pour les nombres pairs et "impair" pour les impairs : `["pair" if x%2==0 else "impair" for x in range(1, 11)]`.

**Exercice 11.5** - Compréhension imbriquée  
Crée une liste de toutes les combinaisons (x, y) où x va de 1 à 3 et y va de 1 à 3, en utilisant : `[(x, y) for x in range(1, 4) for y in range(1, 4)]`.

**Exercice 11.6** - Dictionnaire comprehension  
Crée un dictionnaire avec les nombres de 1 à 5 comme clés et leurs carrés comme valeurs : `{x: x**2 for x in range(1, 6)}`. Crée un dictionnaire qui inverse clés et valeurs d'un dictionnaire existant.

**Exercice 11.7** - Compréhension avec filtrage  
Crée une liste `nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`. Crée un dictionnaire avec seulement les nombres pairs comme clés et leurs cubes comme valeurs : `{x: x**3 for x in nombres if x % 2 == 0}`.

**Exercice 11.8** - Set comprehension  
Crée un set des restes de la division par 3 pour les nombres de 0 à 20 : `{x % 3 for x in range(21)}`. Compare avec une liste comprehension pour voir comment le set élimine les doublons.

**Exercice 11.9** - Compréhension sur dictionnaire  
Crée `scores = {"Alice": 85, "Bob": 92, "Charlie": 78}`. Crée un nouveau dictionnaire avec une bonification de 5 points pour tous : `{nom: score+5 for nom, score in scores.items()}`. Crée un dictionnaire avec seulement ceux qui ont > 80.

**Exercice 11.10** - Compréhension complexe  
Crée une chaîne `texte = "Python est génial"`. Crée un dictionnaire qui compte les occurrences de chaque lettre (ignore les espaces) en utilisant une compréhension et la méthode `.count()`.

---

### **Chapitre 12 — Fonctions lambda et programmation fonctionnelle**

**Exercice 12.1** - Lambda simple  
Crée une fonction lambda qui prend un nombre et retourne son carré : `carre = lambda x: x**2`. Teste-la. Crée aussi des lambdas pour doubler un nombre et pour additionner deux nombres.

**Exercice 12.2** - Lambda avec map  
Crée une liste `nombres = [1, 2, 3, 4, 5]`. Utilise `map()` avec une lambda pour doubler chaque nombre : `list(map(lambda x: x*2, nombres))`. Fais de même pour convertir une liste de températures Celsius en Fahrenheit.

**Exercice 12.3** - Lambda avec filter  
Crée une liste `ages = [12, 17, 18, 21, 16, 25, 30]`. Utilise `filter()` avec une lambda pour garder seulement les majeurs (>= 18) : `list(filter(lambda x: x >= 18, ages))`. Filtre aussi les nombres pairs d'une liste.

**Exercice 12.4** - Sorted avec lambda  
Crée une liste de tuples `personnes = [("Alice", 25), ("Bob", 30), ("Charlie", 20)]`. Trie par âge avec `sorted(personnes, key=lambda x: x[1])`. Trie une liste de mots par longueur.

**Exercice 12.5** - Lambda et reduce  
Importe `reduce` de `functools`. Crée une liste `nombres = [1, 2, 3, 4, 5]`. Utilise reduce avec une lambda pour calculer le produit de tous les nombres : `reduce(lambda x, y: x*y, nombres)`. Calcule aussi la somme.

**Exercice 12.6** - Lambda dans dictionnaires  
Crée un dictionnaire de fonctions : `operations = {"carre": lambda x: x**2, "cube": lambda x: x**3, "double": lambda x: x*2}`. Utilise ces fonctions stockées pour faire des calculs.

**Exercice 12.7** - Max/min avec lambda  
Crée une liste de dictionnaires représentant des produits : `produits = [{"nom": "A", "prix": 30}, {"nom": "B", "prix": 20}]`. Trouve le produit le moins cher avec `min(produits, key=lambda x: x["prix"])`.

**Exercice 12.8** - Lambda avec conditions  
Crée une liste de nombres. Utilise map avec une lambda qui contient une condition if-else pour remplacer les négatifs par 0 : `list(map(lambda x: 0 if x < 0 else x, nombres))`.

**Exercice 12.9** - Chaînage de fonctions  
Crée une liste de nombres. Applique successivement : filter pour garder les pairs, map pour les multiplier par 3, sorted pour les trier. Utilise des lambdas pour chaque opération.

**Exercice 12.10** - Zip avec lambda  
Crée deux listes `noms = ["Alice", "Bob", "Charlie"]` et `scores = [85, 92, 78]`. Utilise `zip()` et `map()` avec une lambda pour créer des chaînes formatées : "Alice: 85", "Bob: 92", etc.

---

## [BRICK] PARTIE 3 — Programmation orientée objet (POO)

---

### **Chapitre 13 — Classes et objets**

**Exercice 13.1** - Première classe  
Crée une classe `Personne` avec un constructeur `__init__` qui prend `nom` et `age`. Crée une méthode `se_presenter()` qui affiche "Je m'appelle [nom] et j'ai [age] ans". Crée 3 instances et fais-les se présenter.

**Exercice 13.2** - Attributs et méthodes  
Crée une classe `Voiture` avec attributs : `marque`, `modele`, `annee`, `kilometrage`. Ajoute des méthodes : `rouler(km)` qui augmente le kilométrage, `afficher_info()` qui affiche toutes les infos.

**Exercice 13.3** - **str** et **repr**  
Crée une classe `Livre` avec `titre`, `auteur`, `pages`. Implémente `__str__()` pour un affichage lisible et `__repr__()` pour une représentation technique. Teste avec `print()` et `repr()`.

**Exercice 13.4** - Compteur d'instances  
Crée une classe `CompteurInstances` avec un attribut de classe (pas d'instance) qui compte combien d'objets ont été créés. Incrémente ce compteur dans `__init__`. Crée plusieurs objets et affiche le compteur.

**Exercice 13.5** - Méthodes de classe  
Crée une classe `Temperature` avec un attribut `celsius`. Ajoute une méthode de classe `@classmethod` nommée `depuis_fahrenheit(cls, f)` qui crée une instance à partir de Fahrenheit : `(f - 32) * 5/9`.

**Exercice 13.6** - Méthodes statiques  
Crée une classe `Mathematiques` avec des méthodes statiques `@staticmethod` : `est_pair(n)`, `est_premier(n)`, `pgcd(a, b)`. Ces méthodes n'ont pas besoin d'instance pour être utilisées.

**Exercice 13.7** - Attributs privés  
Crée une classe `CompteBancaire` avec attributs : `_titulaire` (protégé) et `__solde` (privé). Ajoute méthodes : `deposer(montant)`, `retirer(montant)`, `get_solde()`. Le solde ne peut pas être négatif.

**Exercice 13.8** - Interaction entre objets  
Crée deux classes : `Etudiant` (nom, liste de notes) et `Classe` (nom, liste d'étudiants). Dans Classe, ajoute méthodes : `ajouter_etudiant()`, `moyenne_classe()`, `meilleur_etudiant()`.

**Exercice 13.9** - Opérateurs personnalisés  
Crée une classe `Vecteur` avec attributs `x` et `y`. Implémente `__add__` pour additionner deux vecteurs, `__mul__` pour la multiplication scalaire, `__eq__` pour comparer deux vecteurs.

**Exercice 13.10** - Classe complète  
Crée une classe `Produit` pour un système de gestion de stock : attributs (nom, prix, quantite), méthodes (vendre, reapprovisionner, appliquer_remise, afficher), validations (prix positif, quantité >= 0), et `__str__`.

---

### **Chapitre 14 — Héritage et polymorphisme**

**Exercice 14.1** - Héritage simple  
Crée une classe parente `Animal` avec attributs `nom`, `age` et méthode `parler()`. Crée deux classes enfants `Chien` et `Chat` qui héritent de Animal et redéfinissent `parler()` ("Woof!" et "Meow!").

**Exercice 14.2** - Super()  
Crée une classe `Vehicule` avec `__init__(marque, modele)`. Crée `Voiture(Vehicule)` qui ajoute attribut `nb_portes`. Dans `__init__` de Voiture, utilise `super().__init__(marque, modele)` puis initialise nb_portes.

**Exercice 14.3** - Héritage multi-niveaux  
Crée une hiérarchie : `Etre_Vivant` -> `Animal` -> `Mammifere` -> `Chien`. Chaque classe ajoute des attributs/méthodes. Crée une instance de Chien et vérifie qu'elle hérite de tout.

**Exercice 14.4** - Polymorphisme  
Crée une classe `Forme` avec méthode `aire()`. Crée des classes `Rectangle`, `Cercle`, `Triangle` qui héritent et implémentent leur propre `aire()`. Crée une liste de formes différentes et calcule l'aire de chacune.

**Exercice 14.5** - Method overriding  
Crée une classe `Employe` avec méthode `calculer_salaire()`. Crée `EmployeHoraire` qui calcule salaire = heures \* taux, et `EmployeMensuel` avec salaire fixe. Redéfinis la méthode dans chaque sous-classe.

**Exercice 14.6** - Isinstance et issubclass  
Reprends les classes du 14.1. Utilise `isinstance()` pour vérifier si un objet est une instance de Animal, Chien, Chat. Utilise `issubclass()` pour vérifier les relations d'héritage.

**Exercice 14.7** - Héritage multiple  
Crée deux classes : `Nageur` (méthode nager) et `Voleur` (méthode voler). Crée `Canard` qui hérite des deux et peut donc nager et voler. Gère les conflits potentiels de noms de méthodes.

**Exercice 14.8** - MRO (Method Resolution Order)  
Crée une hiérarchie complexe avec héritage multiple. Utilise `NomClasse.mro()` ou `NomClasse.__mro__` pour afficher l'ordre de résolution des méthodes. Explique l'ordre obtenu.

**Exercice 14.9** - Composition vs héritage  
Crée une classe `Moteur`. Crée `Voiture` qui contient un objet Moteur (composition) plutôt que d'hériter. Compare avec l'héritage : quand utiliser l'un ou l'autre ?

**Exercice 14.10** - Système complet avec héritage  
Crée un système de gestion d'une bibliothèque : classe parente `Document` (titre, auteur, annee), classes enfants `Livre` (pages, isbn), `Magazine` (numero, mois), `DVD` (duree). Chacun implémente `afficher_info()` différemment.

---

### **Chapitre 15 — Encapsulation et propriétés**

**Exercice 15.1** - Getters et setters manuels  
Crée une classe `Rectangle` avec attributs privés `__longueur` et `__largeur`. Crée méthodes `get_longueur()`, `set_longueur(valeur)` qui vérifient que la valeur est positive avant de l'assigner.

**Exercice 15.2** - Propriétés avec @property  
Reprends la classe Rectangle. Utilise le décorateur `@property` pour créer une propriété `longueur` (getter) et `@longueur.setter` pour le setter. Accède maintenant comme un attribut : `rect.longueur = 5`.

**Exercice 15.3** - Propriété calculée  
Crée une classe `Cercle` avec attribut `rayon`. Crée une propriété `aire` (seulement getter) qui calcule et retourne l'aire sans la stocker : `@property def aire(self): return 3.14159 * self.rayon ** 2`.

**Exercice 15.4** - Validation avec setters  
Crée une classe `Personne` avec propriété `age`. Le setter doit vérifier que l'âge est entre 0 et 150, sinon lever une `ValueError`. Teste avec des valeurs valides et invalides.

**Exercice 15.5** - Attributs en lecture seule  
Crée une classe `Produit` avec `__prix`. Crée une propriété `prix` avec seulement un getter (pas de setter). Le prix ne peut être défini que dans `__init__` et ne peut plus être modifié après.

**Exercice 15.6** - Propriétés liées  
Crée une classe `Temperature` avec attribut privé `__celsius`. Crée deux propriétés : `celsius` (getter/setter) et `fahrenheit` (getter/setter). Modifier l'une met automatiquement à jour l'autre.

**Exercice 15.7** - Deleter  
Crée une classe avec une propriété qui a un getter, setter, et deleter `@prop.deleter`. Le deleter réinitialise l'attribut à None ou à une valeur par défaut. Teste avec `del objet.propriete`.

**Exercice 15.8** - Encapsulation complète  
Crée une classe `CompteBancaire` avec tous les attributs privés. Expose seulement ce qui est nécessaire via des propriétés et méthodes publiques. Aucun accès direct aux attributs ne doit être possible de l'extérieur.

**Exercice 15.9** - Propriété avec cache  
Crée une classe avec une propriété qui fait un calcul coûteux (par exemple, factorielle d'un grand nombre). Cache le résultat dans un attribut privé pour ne pas recalculer si la valeur n'a pas changé.

**Exercice 15.10** - Name mangling  
Explore le "name mangling" de Python. Crée une classe avec un attribut `__secret`. Essaie d'y accéder de l'extérieur. Découvre comment y accéder avec `_NomClasse__secret`. Discute des implications.

---

### **Chapitre 16 — Classes abstraites et interfaces**

**Exercice 16.1** - Classe abstraite simple  
Importe `ABC` et `abstractmethod` de `abc`. Crée une classe abstraite `Forme` avec une méthode abstraite `calculer_aire()`. Essaie de l'instancier (erreur). Crée `Carre` qui hérite et implémente la méthode.

**Exercice 16.2** - Multiple méthodes abstraites  
Crée une classe abstraite `Animal` avec méthodes abstraites `manger()`, `dormir()`, `se_deplacer()`. Crée des classes concrètes `Chien`, `Oiseau`, `Poisson` qui implémentent toutes ces méthodes différemment.

**Exercice 16.3** - Méthodes concrètes dans abstraite  
Crée une classe abstraite `Vehicule` avec une méthode abstraite `demarrer()` et une méthode concrète `arreter()` (implémentée). Les classes enfants héritent de `arreter()` mais doivent implémenter `demarrer()`.

**Exercice 16.4** - Interface pure  
Crée une "interface" `Payable` (classe abstraite) avec seulement des méthodes abstraites : `calculer_montant()`, `effectuer_paiement()`. Crée des classes `Facture` et `Salaire` qui l'implémentent.

**Exercice 16.5** - Héritage multiple d'abstraites  
Crée deux classes abstraites `Volant` (méthode voler) et `Nageur` (méthode nager). Crée `Canard` qui hérite des deux et implémente les deux méthodes abstraites.

**Exercice 16.6** - Validation avec abstraites  
Crée une fonction qui prend une liste de `Forme` et calcule la surface totale. Grâce à l'abstraction, la fonction fonctionne avec n'importe quelle forme concrète (Cercle, Rectangle, Triangle).

**Exercice 16.7** - abstractproperty  
Crée une classe abstraite avec une propriété abstraite en utilisant `@property` et `@abstractmethod` combinés. Les classes enfants doivent implémenter cette propriété.

**Exercice 16.8** - Classe abstraite partielle  
Crée une classe abstraite `BaseDeDonnees` avec des méthodes concrètes pour la connexion/déconnexion et des méthodes abstraites pour `lire()`, `ecrire()`. Crée `MySQL` et `PostgreSQL` qui spécialisent les méthodes abstraites.

**Exercice 16.9** - Type checking avec ABC  
Utilise `isinstance()` avec des classes abstraites pour vérifier qu'un objet implémente une interface donnée. Crée une fonction qui n'accepte que des objets implémentant l'interface `Payable`.

**Exercice 16.10** - Design pattern avec ABC  
Implémente le pattern Strategy : crée une classe abstraite `StrategieCalcul` avec méthode abstraite `calculer()`. Crée des stratégies concrètes `Addition`, `Multiplication`. Une classe `Calculatrice` utilise ces stratégies.

---

## [CONFIG] PARTIE 4 — Outils essentiels du développeur Python

---

### **Chapitre 17 — Environnements virtuels**

**Exercice 17.1** - Créer un venv  
Dans le terminal, crée un environnement virtuel avec `python -m venv mon_env`. Observe la structure de dossiers créée (Scripts/bin, Lib, etc.). Liste les fichiers créés.

**Exercice 17.2** - Activer/désactiver venv  
Active l'environnement virtuel (Windows : `mon_env\Scripts\activate`, Linux/Mac : `source mon_env/bin/activate`). Vérifie avec `which python` ou `where python`. Désactive avec `deactivate`.

**Exercice 17.3** - Installer des packages dans venv  
Active ton venv. Installe `requests` avec `pip install requests`. Vérifie avec `pip list`. Désactive le venv et vérifie que requests n'est pas dans l'environnement global.

**Exercice 17.4** - Requirements.txt  
Dans un venv activé, installe plusieurs packages (requests, pandas, etc.). Génère un fichier requirements.txt avec `pip freeze > requirements.txt`. Ouvre et observe le fichier.

**Exercice 17.5** - Recréer environnement  
Crée un nouveau venv vide. Active-le. Installe tous les packages d'un coup avec `pip install -r requirements.txt`. Vérifie que tous les packages sont installés.

**Exercice 17.6** - Plusieurs environnements  
Crée deux venvs différents pour deux projets. Dans l'un, installe numpy version 1.21, dans l'autre version 1.24. Vérifie que chaque environnement a sa propre version isolée.

**Exercice 17.7** - Venv avec version Python spécifique  
Si tu as plusieurs versions de Python installées, crée un venv avec une version spécifique : `python3.9 -m venv mon_env39`. Vérifie la version avec `python --version` après activation.

**Exercice 17.8** - Gitignore et venv  
Crée un fichier `.gitignore` pour ton projet. Ajoute le dossier de ton venv dedans (par exemple `mon_env/`). Explique pourquoi on ne versionne jamais les environnements virtuels.

**Exercice 17.9** - Problèmes courants  
Désactive ton venv. Essaie d'exécuter un script qui importe un package installé seulement dans le venv. Observe l'erreur. Réactive le venv et ré-essaie.

**Exercice 17.10** - Bonnes pratiques  
Documente les bonnes pratiques : un venv par projet, activer avant d'installer, nommer clairement (venv, env, .venv), toujours inclure requirements.txt. Crée un README.md expliquant comment installer ton projet.

---

### **Chapitre 18 — Gestion des dépendances**

**Exercice 18.1** - Installer version spécifique  
Installe une version précise d'un package : `pip install requests==2.28.0`. Vérifie avec `pip show requests`. Installe ensuite `requests>=2.25.0` et observe quelle version est installée.

**Exercice 18.2** - Mettre à jour packages  
Installe un package, puis mets-le à jour avec `pip install --upgrade requests`. Compare les versions avant/après avec `pip show`. Liste tous les packages obsolètes avec `pip list --outdated`.

**Exercice 18.3** - Désinstaller proprement  
Installe un package avec ses dépendances. Désinstalle-le avec `pip uninstall package`. Vérifie avec `pip list` si les dépendances sont restées. Nettoie-les si nécessaire.

**Exercice 18.4** - Requirements détaillés  
Crée un requirements.txt avec différents formats de versions : `requests==2.28.0` (exacte), `pandas>=1.3.0` (minimum), `numpy>=1.20,<1.25` (plage). Installe et observe.

**Exercice 18.5** - Requirements multiples  
Crée plusieurs fichiers : `requirements-base.txt` (dépendances prod), `requirements-dev.txt` (outils dev comme pytest, black). Installe la base, puis le dev avec `pip install -r requirements-dev.txt`.

**Exercice 18.6** - Pip freeze vs pipreqs  
Compare `pip freeze` (tous les packages) avec `pipreqs` (seulement utilisés). Installe pipreqs, exécute `pipreqs .` dans ton projet. Compare les deux fichiers générés.

**Exercice 18.7** - Dépendances en conflit  
Installe volontairement deux packages qui ont des dépendances conflictuelles. Observe les messages d'erreur ou avertissements de pip. Résous le conflit en spécifiant les versions compatibles.

**Exercice 18.8** - Pip check  
Après avoir installé plusieurs packages, exécute `pip check` pour vérifier les dépendances manquantes ou incompatibles. Corrige les problèmes trouvés.

**Exercice 18.9** - Cache pip  
Utilise `pip cache list` pour voir le cache. Installe un package, désinstalle-le, réinstalle-le et observe que c'est plus rapide (utilise le cache). Nettoie le cache avec `pip cache purge`.

**Exercice 18.10** - Lock dependencies  
Crée un requirements.txt "lockfile" avec toutes les versions exactes (pip freeze). Documente pourquoi c'est important en production pour la reproductibilité. Crée aussi un requirements-loose.txt avec versions flexibles pour le développement.

---

### **Chapitre 19 — Logging et debugging**

**Exercice 19.1** - Logging basique  
Importe `logging`. Configure avec `logging.basicConfig(level=logging.DEBUG)`. Utilise les différents niveaux : `logging.debug()`, `.info()`, `.warning()`, `.error()`, `.critical()`. Observe ce qui s'affiche selon le niveau configuré.

**Exercice 19.2** - Logging dans fichier  
Configure logging pour écrire dans un fichier : `logging.basicConfig(filename='app.log', level=logging.INFO)`. Écris plusieurs logs, puis ouvre et lis le fichier.

**Exercice 19.3** - Format personnalisé  
Configure un format de log personnalisé incluant : timestamp, niveau, message. Utilise : `logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')`.

**Exercice 19.4** - Logging dans fonctions  
Crée plusieurs fonctions. Ajoute des logs au début et à la fin de chaque fonction pour tracer l'exécution. Utilise différents niveaux selon l'importance (debug pour traces détaillées, info pour étapes importantes).

**Exercice 19.5** - Logger nommés  
Crée des loggers nommés : `logger = logging.getLogger(__name__)`. Crée plusieurs modules avec chacun son logger. Configure différemment le niveau de log pour chaque module.

**Exercice 19.6** - Handlers multiples  
Configure logging avec plusieurs handlers : un pour la console (niveau INFO), un pour un fichier (niveau DEBUG), un pour les erreurs (niveau ERROR dans errors.log).

**Exercice 19.7** - Debugging avec print  
Crée une fonction bugguée. Utilise des `print()` stratégiques pour comprendre le flow et trouver le bug. Affiche les valeurs des variables à différentes étapes.

**Exercice 19.8** - pdb debugger  
Utilise `import pdb; pdb.set_trace()` ou `breakpoint()` dans ton code. Exécute et explore les commandes : `n` (next), `s` (step), `c` (continue), `l` (list), `p variable` (print). Débugue une fonction qui calcule mal.

**Exercice 19.9** - Logging d'exceptions  
Crée un programme qui peut générer des exceptions. Dans le bloc except, utilise `logging.exception("Message")` pour logger automatiquement l'erreur avec le traceback complet.

**Exercice 19.10** - Système de logging complet  
Crée un programme de calculatrice avec logging complet : logs info pour chaque opération, warning pour divisions par zéro tentées, error pour entrées invalides, debug pour valeurs intermédiaires. Sauvegarde tout dans un fichier avec rotation.

---

### **Chapitre 20 — Tests unitaires et TDD**

**Exercice 20.1** - Premier test unittest  
Crée une fonction `addition(a, b)`. Crée un fichier `test_calcul.py`. Importe `unittest`. Crée une classe `TestAddition(unittest.TestCase)` avec méthode `test_addition_positifs()` qui teste avec `self.assertEqual()`.

**Exercice 20.2** - Tests multiples  
Crée des fonctions mathématiques (addition, soustraction, multiplication, division). Pour chacune, crée au moins 3 tests : nombres positifs, négatifs, et cas limites (zéro, division par zéro).

**Exercice 20.3** - setUp et tearDown  
Crée une classe de test avec `setUp()` (exécuté avant chaque test) et `tearDown()` (après chaque test). Utilise setUp pour initialiser des données de test communes.

**Exercice 20.4** - Assertions variées  
Teste une fonction avec différentes assertions : `assertEqual`, `assertNotEqual`, `assertTrue`, `assertFalse`, `assertIn`, `assertIsInstance`, `assertRaises` (pour les exceptions).

**Exercice 20.5** - Test exceptions  
Crée une fonction `diviser(a, b)` qui lève `ValueError` si b=0. Teste cette exception avec `with self.assertRaises(ValueError): diviser(5, 0)`.

**Exercice 20.6** - pytest basique  
Installe pytest (`pip install pytest`). Crée des fonctions de test simples qui commencent par `test_`. Utilise `assert` simple. Exécute avec `pytest` dans le terminal.

**Exercice 20.7** - Fixtures pytest  
Crée une fixture avec `@pytest.fixture` qui retourne des données de test. Utilise cette fixture comme paramètre dans tes fonctions de test. Explore les différents scopes (function, class, module).

**Exercice 20.8** - Parametrize  
Utilise `@pytest.mark.parametrize` pour tester une fonction avec plusieurs jeux de données en un seul test : `@pytest.mark.parametrize("a,b,expected", [(1,2,3), (5,5,10), (-1,1,0)])`.

**Exercice 20.9** - Coverage  
Installe pytest-cov (`pip install pytest-cov`). Exécute tes tests avec `pytest --cov=mon_module`. Observe le rapport de couverture. Identifie les lignes non testées et ajoute des tests.

**Exercice 20.10** - TDD complet  
Pratique le TDD : écris d'abord un test pour une fonction `calculer_moyenne(liste)` qui n'existe pas encore (test échoue). Puis implémente la fonction minimalement pour que le test passe. Ajoute plus de tests (liste vide, etc.) et améliore la fonction.

---

## [WEB] PARTIE 5 — Python pour le Web

---

### **Chapitre 21 — Serveurs web et HTTP**

**Exercice 21.1** - Serveur HTTP simple  
Importe `http.server`. Lance un serveur local avec `python -m http.server 8000`. Ouvre `localhost:8000` dans ton navigateur. Observe les fichiers du répertoire. Arrête avec Ctrl+C.

**Exercice 21.2** - Requête GET avec requests  
Installe requests. Fais une requête GET à `https://api.github.com/users/python`. Affiche le status code, les headers, et le contenu JSON avec `.json()`.

**Exercice 21.3** - Gestion des erreurs HTTP  
Fais une requête vers une URL invalide. Capture l'exception avec try-except. Teste aussi une URL valide qui retourne 404. Vérifie le status code avec `response.raise_for_status()`.

**Exercice 21.4** - Paramètres de requête  
Fais une requête GET avec paramètres : `requests.get(url, params={"q": "python", "sort": "stars"})`. Affiche l'URL complète générée. Teste avec une API publique comme GitHub ou une API météo.

**Exercice 21.5** - Headers personnalisés  
Envoie une requête avec des headers personnalisés : `headers = {"User-Agent": "MonApp/1.0", "Accept": "application/json"}`. Vérifie l'impact sur la réponse.

**Exercice 21.6** - POST avec JSON  
Fais une requête POST vers une API de test (comme httpbin.org/post). Envoie des données JSON : `requests.post(url, json={"nom": "Ali", "age": 25})`. Affiche la réponse.

**Exercice 21.7** - Télécharger un fichier  
Télécharge une image depuis une URL avec requests. Sauvegarde-la localement en écrivant `response.content` dans un fichier en mode binaire 'wb'.

**Exercice 21.8** - Sessions  
Utilise `session = requests.Session()` pour maintenir des cookies entre plusieurs requêtes. Fais plusieurs requêtes avec la même session vers un site qui utilise des cookies.

**Exercice 21.9** - Timeout et retry  
Fais une requête avec timeout : `requests.get(url, timeout=5)`. Implémente une logique de retry : si la requête échoue, réessaie 3 fois avec un délai croissant.

**Exercice 21.10** - API complète  
Crée un programme qui interagit avec une API publique (ex: OpenWeatherMap). Demande une ville à l'utilisateur, fait la requête, parse le JSON, affiche la météo formatée joliment.

---

### **Chapitre 22 — Introduction à Flask et FastAPI**

**Exercice 22.1** - Hello Flask  
Installe Flask. Crée `app.py` avec :

```python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
    return "Hello Flask!"
```

Lance avec `flask run`. Visite `localhost:5000`.

**Exercice 22.2** - Routes multiples  
Crée plusieurs routes : `/`, `/about`, `/contact`. Chacune retourne un message différent. Teste dans le navigateur.

**Exercice 22.3** - Paramètres d'URL  
Crée une route avec paramètre : `@app.route('/user/<name>')`. Utilise ce paramètre dans la fonction : `return f"Bonjour {name}!"`. Teste avec différents noms.

**Exercice 22.4** - Templates Flask  
Crée un dossier `templates/`. Crée `index.html` avec du HTML. Dans Flask, utilise `render_template('index.html', nom=nom)` pour passer des variables au template avec Jinja2.

**Exercice 22.5** - Formulaire POST  
Crée un formulaire HTML qui envoie des données en POST. Dans Flask, gère avec `request.form.get()`. Affiche les données reçues.

**Exercice 22.6** - JSON API Flask  
Crée une route qui retourne du JSON : `return jsonify({"message": "Hello", "status": "success"})`. Teste avec curl ou un client REST.

**Exercice 22.7** - Hello FastAPI  
Installe FastAPI et uvicorn. Crée une application FastAPI simple :

```python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
    return {"message": "Hello FastAPI"}
```

Lance avec `uvicorn main:app --reload`.

**Exercice 22.8** - Path parameters FastAPI  
Crée une route FastAPI avec path parameter typé : `@app.get("/items/{item_id}")` avec `def read_item(item_id: int)`. FastAPI valide automatiquement le type.

**Exercice 22.9** - Query parameters  
Crée une route avec query parameters : `def read_items(skip: int = 0, limit: int = 10)`. Teste avec `localhost:8000/items?skip=5&limit=20`.

**Exercice 22.10** - Pydantic models  
Crée un modèle Pydantic pour valider les données POST :

```python
from pydantic import BaseModel
class Item(BaseModel):
    name: str
    price: float
```

Crée une route POST qui accepte ce modèle.

---

### **Chapitre 23 — Django pour le web complet**

**Exercice 23.1** - Installation Django  
Installe Django. Crée un projet : `django-admin startproject monprojet`. Explore la structure créée (settings.py, urls.py, manage.py). Lance le serveur : `python manage.py runserver`.

**Exercice 23.2** - Première app  
Crée une application : `python manage.py startapp blog`. Ajoute-la dans `INSTALLED_APPS` du settings.py. Crée une vue simple dans `blog/views.py`.

**Exercice 23.3** - URLs et vues  
Configure les URLs dans `blog/urls.py` et inclus-les dans le projet. Crée plusieurs vues (liste d'articles, détail d'article). Teste dans le navigateur.

**Exercice 23.4** - Templates Django  
Crée des templates dans `blog/templates/blog/`. Utilise le langage de template Django avec `{% %}` et `{{ }}`. Hérite d'un template de base avec `{% extends %}` et `{% block %}`.

**Exercice 23.5** - Modèles de données  
Crée un modèle `Article` dans `models.py` avec champs : titre, contenu, date_publication, auteur. Fais les migrations : `python manage.py makemigrations` puis `python manage.py migrate`.

**Exercice 23.6** - Admin Django  
Crée un superuser : `python manage.py createsuperuser`. Enregistre ton modèle Article dans `admin.py` : `admin.site.register(Article)`. Accède à l'admin et crée des articles.

**Exercice 23.7** - ORM queries  
Dans une vue, utilise l'ORM Django : `Article.objects.all()`, `.filter(titre__contains="Python")`, `.get(id=1)`, `.order_by('-date_publication')`. Affiche les résultats.

**Exercice 23.8** - Formulaires Django  
Crée un formulaire avec `forms.Form` ou `forms.ModelForm`. Affiche-le dans un template. Gère la soumission dans une vue avec validation.

**Exercice 23.9** - Relations entre modèles  
Crée un modèle `Categorie` et ajoute une ForeignKey dans Article. Explore les relations : `article.categorie`, `categorie.article_set.all()`. Teste les requêtes liées.

**Exercice 23.10** - Authentification  
Utilise le système d'authentification Django. Crée des vues de login/logout. Protège certaines vues avec le décorateur `@login_required`. Affiche l'utilisateur connecté dans les templates.

---

## [CALCUL] PARTIE 6 — Python pour la Data et l'IA

---

### **Chapitre 24 — Numpy et Pandas**

**Exercice 24.1** - Arrays Numpy  
Installe numpy. Crée des arrays : `np.array([1,2,3])`, `np.zeros((3,3))`, `np.ones((2,4))`, `np.arange(0,10,2)`, `np.linspace(0,1,5)`. Affiche leurs formes avec `.shape`.

**Exercice 24.2** - Opérations sur arrays  
Crée deux arrays. Fais des opérations élément par élément : addition, multiplication, puissance. Compare avec des listes Python (les arrays sont plus rapides et concis).

**Exercice 24.3** - Indexing et slicing  
Crée un array 2D. Accède à des éléments spécifiques, des lignes, des colonnes, des sous-matrices avec slicing : `arr[0,:]`, `arr[:,1]`, `arr[1:3, 0:2]`.

**Exercice 24.4** - Fonctions Numpy  
Utilise : `np.sum()`, `np.mean()`, `np.std()`, `np.min()`, `np.max()`, `np.argmax()`. Teste avec axis=0 (colonnes) et axis=1 (lignes) sur un array 2D.

**Exercice 24.5** - DataFrame Pandas  
Installe pandas. Crée un DataFrame depuis un dictionnaire : `pd.DataFrame({"nom": ["Ali", "Sara"], "age": [25, 30]})`. Affiche avec `.head()`, `.info()`, `.describe()`.

**Exercice 24.6** - Lire CSV  
Crée un fichier CSV avec des données (ou télécharge-en un). Lis-le avec `pd.read_csv()`. Explore : colonnes, shape, types de données. Affiche les premières et dernières lignes.

**Exercice 24.7** - Sélection de données  
Sélectionne des colonnes : `df['nom']`, `df[['nom', 'age']]`. Filtre des lignes : `df[df['age'] > 25]`. Combine : `df[df['age'] > 25]['nom']`. Utilise `.loc[]` et `.iloc[]`.

**Exercice 24.8** - Groupby et agrégation  
Crée un DataFrame avec des ventes par produit et région. Utilise `.groupby('region')['ventes'].sum()` pour agréger. Essaie aussi `.mean()`, `.count()`, `.agg(['sum', 'mean'])`.

**Exercice 24.9** - Gestion des valeurs manquantes  
Crée un DataFrame avec des NaN. Détecte-les avec `.isnull()`, `.isna()`. Supprime avec `.dropna()`, remplace avec `.fillna(0)` ou `.fillna(method='ffill')`.

**Exercice 24.10** - Manipulation avancée  
Merge deux DataFrames avec `.merge()`. Concatene avec `pd.concat()`. Pivot avec `.pivot_table()`. Applique une fonction avec `.apply()`. Crée de nouvelles colonnes calculées.

---

### **Chapitre 25 — Visualisation**

**Exercice 25.1** - Plot simple Matplotlib  
Installe matplotlib. Crée des listes x et y. Plot : `plt.plot(x, y)`, `plt.xlabel()`, `plt.ylabel()`, `plt.title()`, `plt.show()`. Crée un graphique de fonction mathématique (sin, cos).

**Exercice 25.2** - Types de graphiques  
Crée : un line plot, un scatter plot (`plt.scatter()`), un bar chart (`plt.bar()`), un histogram (`plt.hist()`). Utilise des données différentes pour chaque type.

**Exercice 25.3** - Sous-graphiques  
Utilise `plt.subplot(2, 2, 1)` pour créer une grille de 4 graphiques. Affiche différents types de visualisations dans chaque sous-graphique.

**Exercice 25.4** - Personnalisation  
Personnalise un graphique : couleurs, styles de ligne, marqueurs, grille, légende, taille de la figure (`plt.figure(figsize=(10,6))`), sauvegarde avec `plt.savefig()`.

**Exercice 25.5** - Seaborn basique  
Installe seaborn. Crée un DataFrame. Utilise `sns.lineplot()`, `sns.scatterplot()`, `sns.barplot()`. Compare avec matplotlib : seaborn est plus joli par défaut.

**Exercice 25.6** - Visualisation de distributions  
Utilise seaborn pour : `sns.histplot()` (histogramme), `sns.boxplot()` (boîte à moustaches), `sns.violinplot()` (violin plot). Visualise la distribution d'une variable numérique.

**Exercice 25.7** - Heatmap  
Crée une matrice de corrélation avec `df.corr()`. Visualise avec `sns.heatmap(df.corr(), annot=True, cmap='coolwarm')`. Interprète les résultats.

**Exercice 25.8** - Pairplot  
Utilise `sns.pairplot(df)` pour visualiser toutes les relations entre variables d'un DataFrame. Colore par catégorie avec le paramètre `hue`.

**Exercice 25.9** - Plotly interactif  
Installe plotly. Crée un graphique interactif : `import plotly.express as px; fig = px.line(df, x='date', y='valeur'); fig.show()`. Explore les interactions (zoom, hover, etc.).

**Exercice 25.10** - Dashboard simple  
Crée un programme qui charge des données, calcule des statistiques, et génère automatiquement 4-5 visualisations différentes (line, bar, scatter, heatmap) sauvegardées en PNG.

---

### **Chapitre 26 — Machine Learning**

**Exercice 26.1** - Premier modèle sklearn  
Installe scikit-learn. Charge un dataset simple : `from sklearn.datasets import load_iris; iris = load_iris()`. Explore les données : features, target, target_names.

**Exercice 26.2** - Train/Test split  
Utilise `from sklearn.model_selection import train_test_split`. Divise tes données : `X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)`.

**Exercice 26.3** - Régression linéaire  
Importe `from sklearn.linear_model import LinearRegression`. Crée un modèle, entraîne avec `.fit(X_train, y_train)`, prédis avec `.predict(X_test)`. Évalue avec score R².

**Exercice 26.4** - Classification K-NN  
Utilise `from sklearn.neighbors import KNeighborsClassifier`. Entraîne sur le dataset Iris. Prédis les classes. Calcule l'accuracy avec `accuracy_score(y_test, y_pred)`.

**Exercice 26.5** - Arbre de décision  
Utilise `DecisionTreeClassifier`. Entraîne, prédis, évalue. Visualise l'arbre avec `plot_tree()`. Comprends les paramètres `max_depth`, `min_samples_split`.

**Exercice 26.6** - Matrice de confusion  
Après une prédiction, affiche la matrice de confusion : `from sklearn.metrics import confusion_matrix, classification_report`. Interprète les vrais/faux positifs/négatifs.

**Exercice 26.7** - Normalisation  
Utilise `from sklearn.preprocessing import StandardScaler`. Normalise tes features avant l'entraînement : `scaler.fit_transform(X_train)`, `scaler.transform(X_test)`. Compare les performances avec/sans.

**Exercice 26.8** - Cross-validation  
Utilise `from sklearn.model_selection import cross_val_score`. Évalue ton modèle avec validation croisée sur 5 folds. Compare les scores obtenus.

**Exercice 26.9** - GridSearch  
Utilise `GridSearchCV` pour trouver les meilleurs hyperparamètres d'un modèle. Teste différentes valeurs de paramètres et affiche les meilleurs.

**Exercice 26.10** - Pipeline complet  
Crée un pipeline ML complet : chargement données -> nettoyage -> normalisation -> split -> entraînement -> évaluation -> sauvegarde modèle avec `joblib`. Charge et réutilise le modèle.

---

## [BOITE_A_OUTILS] PARTIE 7 — Python avancé (niveau expert)

---

### **Chapitre 27 — Générateurs et itérateurs**

**Exercice 27.1** - Premier générateur  
Crée une fonction générateur avec `yield` qui génère les nombres de 1 à 10. Utilise-la dans une boucle for. Compare avec une fonction qui retourne une liste.

**Exercice 27.2** - Yield multiple  
Crée un générateur qui yield plusieurs valeurs. Appelle `next()` manuellement sur le générateur pour obtenir les valeurs une par une. Gère le `StopIteration`.

**Exercice 27.3** - Générateur infini  
Crée un générateur infini qui génère tous les nombres pairs : `def pairs(): n=0; while True: yield n; n+=2`. Utilise-le avec une limite pour ne pas boucler infiniment.

**Exercice 27.4** - Expression génératrice  
Crée une expression génératrice (comme une list comprehension mais avec `()`) : `(x**2 for x in range(1000000))`. Compare la mémoire utilisée avec une liste comprehension.

**Exercice 27.5** - Fibonacci générateur  
Crée un générateur de nombres de Fibonacci. Chaque appel à next() retourne le nombre suivant de la séquence. Génère les 20 premiers.

**Exercice 27.6** - Générateur de fichiers  
Crée un générateur qui lit un fichier ligne par ligne et yield chaque ligne. C'est plus efficace en mémoire que de charger tout le fichier.

**Exercice 27.7** - Iterator protocol  
Crée une classe qui implémente `__iter__()` et `__next__()` pour être un itérateur. Crée un itérateur personnalisé qui génère la suite des carrés.

**Exercice 27.8** - itertools  
Explore le module itertools : `count()`, `cycle()`, `repeat()`, `chain()`, `combinations()`, `permutations()`. Crée des exemples pour chacun.

**Exercice 27.9** - Pipeline de générateurs  
Chaîne plusieurs générateurs : un qui lit un fichier, un qui filtre les lignes, un qui transforme. C'est efficace en mémoire car tout est lazy.

**Exercice 27.10** - Coroutines  
Explore les générateurs comme coroutines. Utilise `.send()` pour envoyer des valeurs dans un générateur. Crée un exemple de moyenne glissante.

---

### **Chapitre 28 — Décorateurs**

**Exercice 28.1** - Premier décorateur  
Crée un décorateur `@timer` qui mesure le temps d'exécution d'une fonction en utilisant `time.time()`. Applique-le à plusieurs fonctions.

**Exercice 28.2** - Décorateur logger  
Crée un décorateur `@logger` qui affiche "Début de fonction" avant l'exécution et "Fin de fonction" après. Affiche aussi le nom de la fonction avec `func.__name__`.

**Exercice 28.3** - Décorateur avec arguments  
Crée un décorateur `@repeat(n)` qui exécute une fonction n fois. Syntaxe : `@repeat(3)` puis `def ma_fonction():`. Comprends les 3 niveaux de fonctions imbriquées.

**Exercice 28.4** - Wraps et métadonnées  
Utilise `from functools import wraps` dans tes décorateurs pour préserver les métadonnées de la fonction décorée (`__name__`, `__doc__`). Compare avec/sans wraps.

**Exercice 28.5** - Décorateur de cache  
Crée un décorateur `@cache` qui met en cache les résultats d'une fonction. Si la fonction est appelée avec les mêmes arguments, retourne le résultat du cache. Teste avec une fonction coûteuse (calcul factorielle).

**Exercice 28.6** - Décorateur d'authentification  
Crée un décorateur `@require_auth` qui vérifie si un utilisateur est authentifié avant d'exécuter une fonction. Simule l'authentification avec une variable globale.

**Exercice 28.7** - Décorateurs multiples  
Applique plusieurs décorateurs à une même fonction : `@timer`, `@logger`, `@cache`. Observe l'ordre d'exécution (de bas en haut). Teste différents ordres.

**Exercice 28.8** - Décorateur de classe  
Crée un décorateur qui peut être appliqué à une classe entière et qui ajoute automatiquement une méthode `__str__` à toutes les instances.

**Exercice 28.9** - Décorateur avec état  
Crée un décorateur qui compte combien de fois une fonction a été appelée. Stocke le compteur comme attribut de la fonction wrapper.

**Exercice 28.10** - Décorateurs pratiques  
Crée plusieurs décorateurs utiles : `@deprecated` (avertit que la fonction est obsolète), `@retry(n)` (réessaie n fois en cas d'erreur), `@validate_types` (vérifie les types des arguments).

---

### **Chapitre 29 — Context managers**

**Exercice 29.1** - Comprendre with  
Utilise `with open()` pour ouvrir un fichier. Affiche le fichier avant et après le bloc with avec `print(f.closed)`. Comprends que `__exit__` ferme automatiquement.

**Exercice 29.2** - Context manager manuel  
Crée une classe avec `__enter__` et `__exit__`. `__enter__` affiche "Début", `__exit__` affiche "Fin". Utilise-la avec `with MonContext():`.

**Exercice 29.3** - Context manager pour timer  
Crée un context manager `Timer` qui mesure le temps d'exécution du code dans le bloc with. Affiche le temps dans `__exit__`.

**Exercice 29.4** - Gestion d'erreurs  
Dans `__exit__`, reçois les paramètres `exc_type, exc_val, exc_tb`. Si une exception est levée dans le bloc with, affiche-la et retourne True pour la supprimer ou False pour la propager.

**Exercice 29.5** - Context manager avec contextlib  
Utilise `from contextlib import contextmanager` et le décorateur pour créer un context manager avec une fonction et `yield` : plus simple qu'une classe.

**Exercice 29.6** - Connexion base de données  
Crée un context manager pour gérer une connexion SQLite : ouvre dans `__enter__`, commit et ferme dans `__exit__`, rollback si erreur.

**Exercice 29.7** - Suppression temporaire  
Crée un context manager `temporary_attr` qui modifie temporairement un attribut d'un objet, puis le restaure à sa valeur originale en sortant du bloc.

**Exercice 29.8** - Context managers multiples  
Utilise plusieurs context managers dans un seul with : `with open('f1') as f1, open('f2') as f2:`. Crée un exemple qui copie le contenu d'un fichier à un autre.

**Exercice 29.9** - ExitStack  
Utilise `contextlib.ExitStack()` pour gérer un nombre variable de context managers. Utile quand tu ne sais pas à l'avance combien de ressources ouvrir.

**Exercice 29.10** - Context manager réutilisable  
Crée un context manager `WorkingDirectory` qui change temporairement le répertoire de travail puis le restaure. Combine avec logging pour tracer les changements.

---

### **Chapitre 30 — Multithreading et multiprocessing**

**Exercice 30.1** - Premier thread  
Importe `threading`. Crée une fonction qui affiche des nombres. Lance-la dans un thread : `t = threading.Thread(target=ma_fonction); t.start(); t.join()`.

**Exercice 30.2** - Threads multiples  
Crée 5 threads qui exécutent la même fonction avec des paramètres différents. Utilise `.start()` sur chacun puis `.join()` pour attendre qu'ils finissent tous.

**Exercice 30.3** - Threading avec arguments  
Passe des arguments à une fonction thread : `Thread(target=fonction, args=(arg1, arg2))`. Crée des threads qui téléchargent plusieurs URLs en parallèle.

**Exercice 30.4** - Lock et synchronisation  
Crée une variable partagée. Plusieurs threads la modifient. Sans Lock, observe les race conditions. Ajoute `lock = threading.Lock()` et `with lock:` pour synchroniser.

**Exercice 30.5** - Premier Process  
Importe `multiprocessing`. Crée un Process : `p = multiprocessing.Process(target=fonction); p.start(); p.join()`. Compare avec threading.

**Exercice 30.6** - Pool de processus  
Utilise `multiprocessing.Pool(4)` pour créer un pool de 4 processus. Utilise `.map()` pour distribuer du travail (par exemple, calculs lourds) sur tous les processus.

**Exercice 30.7** - Comparaison Thread vs Process  
Crée une tâche CPU-intensive (calcul de nombres premiers). Lance avec threads puis avec processes. Mesure le temps : processes sont plus rapides pour CPU grâce au GIL.

**Exercice 30.8** - Queue pour communication  
Utilise `queue.Queue()` pour la communication entre threads, ou `multiprocessing.Queue()` pour les processes. Un producteur ajoute, un consommateur retire.

**Exercice 30.9** - Thread Pool Executor  
Utilise `from concurrent.futures import ThreadPoolExecutor`. Plus simple que threading : `with ThreadPoolExecutor(max_workers=5) as executor: results = executor.map(fonction, data)`.

**Exercice 30.10** - Cas d'usage réel  
Crée un web scraper qui télécharge 10 pages web en parallèle avec ThreadPoolExecutor (I/O-bound). Compare le temps avec/sans parallélisme.

---

### **Chapitre 31 — Async/Await**

**Exercice 31.1** - Premier async  
Crée une fonction async : `async def ma_fonction(): await asyncio.sleep(1)`. Exécute-la avec `asyncio.run(ma_fonction())`. Comprends qu'on ne peut pas juste l'appeler.

**Exercice 31.2** - Await multiple  
Crée plusieurs fonctions async. Dans une fonction principale, await-les séquentiellement. Mesure le temps : c'est toujours séquentiel si tu attends une par une.

**Exercice 31.3** - Gather pour parallélisme  
Utilise `await asyncio.gather(tache1(), tache2(), tache3())` pour exécuter plusieurs coroutines en parallèle. Mesure : c'est plus rapide que séquentiel.

**Exercice 31.4** - Create_task  
Crée des tasks avec `task = asyncio.create_task(ma_coroutine())`. Les tasks commencent immédiatement. Await-les plus tard pour récupérer les résultats.

**Exercice 31.5** - HTTP async avec aiohttp  
Installe aiohttp. Fais des requêtes HTTP asynchrones : `async with aiohttp.ClientSession() as session: async with session.get(url) as response:`. Télécharge plusieurs URLs en parallèle.

**Exercice 31.6** - Async comprehension  
Utilise des async comprehensions : `[await fetch(url) for url in urls]` ou mieux `await asyncio.gather(*[fetch(url) for url in urls])`.

**Exercice 31.7** - Async context managers  
Crée un context manager async avec `__aenter__` et `__aexit__`. Utilise-le avec `async with MonContextAsync():`. Exemple : connexion async à une base de données.

**Exercice 31.8** - Async generators  
Crée un générateur async : `async def gen(): for i in range(10): await asyncio.sleep(0.1); yield i`. Consomme avec `async for item in gen():`.

**Exercice 31.9** - Timeout et cancellation  
Utilise `asyncio.wait_for(coroutine, timeout=5)` pour limiter le temps. Gère `asyncio.TimeoutError`. Utilise aussi `task.cancel()` pour annuler une task.

**Exercice 31.10** - Application async complète  
Crée un scraper async qui télécharge 50 pages web, parse le HTML, extrait des données, et sauvegarde en base. Compare les performances avec la version synchrone.

---

### **Chapitre 32 — Métaprogrammation**

**Exercice 32.1** - Type et type()  
Utilise `type()` pour obtenir le type d'objets. Crée une classe dynamiquement avec `type('MaClasse', (object,), {'attribut': 42})`. Instancie et teste.

**Exercice 32.2** - Getattr et setattr  
Crée un objet. Utilise `getattr(obj, 'attribut', default)` pour obtenir un attribut dynamiquement. Utilise `setattr(obj, 'nouvel_attr', valeur)` pour en créer un. Utilise `hasattr()` pour tester l'existence.

**Exercice 32.3** - Delattr et vars  
Utilise `delattr(obj, 'attribut')` pour supprimer un attribut. Utilise `vars(obj)` ou `obj.__dict__` pour obtenir tous les attributs d'un objet sous forme de dictionnaire.

**Exercice 32.4** - Introspection avec inspect  
Importe `inspect`. Utilise `inspect.signature(fonction)` pour obtenir les paramètres, `inspect.getsource(fonction)` pour le code source, `inspect.isfunction()`, `inspect.isclass()`.

**Exercice 32.5** - **getattr** et **setattr**  
Crée une classe avec `__getattr__(self, name)` (appelé quand l'attribut n'existe pas) et `__setattr__(self, name, value)`. Crée un objet qui accepte n'importe quel attribut.

**Exercice 32.6** - **getattribute**  
Implémente `__getattribute__` qui est appelé pour TOUS les accès d'attributs. Attention aux récursions infinies : utilise `object.__getattribute__(self, name)` pour accéder vraiment à l'attribut.

**Exercice 32.7** - Descripteurs  
Crée un descripteur (classe avec `__get__`, `__set__`, `__delete__`). Utilise-le comme attribut de classe pour valider les types ou valeurs automatiquement.

**Exercice 32.8** - **call**  
Crée une classe avec `__call__` pour rendre les instances appelables comme des fonctions. Crée un compteur d'appels : `obj()` incrémente et affiche.

**Exercice 32.9** - Metaclasses  
Crée une metaclasse qui hérite de `type`. La metaclasse modifie automatiquement toutes les classes qui l'utilisent (par exemple, ajoute une méthode ou un attribut de classe).

**Exercice 32.10** - Système de plugins  
Utilise la métaprogrammation pour créer un système de plugins : scanne un dossier, importe dynamiquement tous les modules Python, instancie les classes qui héritent d'une classe de base.

---

## [MODULE] PARTIE 8 — Devenir un vrai expert Python

---

### **Chapitre 33 — Structurer un projet pro**

**Exercice 33.1** - Arborescence standard  
Crée une structure de projet : `monprojet/`, `src/monprojet/`, `tests/`, `docs/`, `README.md`, `requirements.txt`, `.gitignore`, `setup.py`. Documente chaque dossier.

**Exercice 33.2** - **init**.py  
Crée un package avec plusieurs modules. Utilise `__init__.py` pour exposer certaines fonctions/classes au niveau du package : `from .module import fonction`.

**Exercice 33.3** - Configuration  
Crée un système de configuration : fichier `config.ini` ou `config.yaml`. Utilise `configparser` ou `pyyaml` pour le lire. Sépare config dev/test/prod.

**Exercice 33.4** - Variables d'environnement  
Utilise `os.environ.get('VAR_NAME')` ou le module `python-dotenv` pour charger des variables d'environnement depuis un fichier `.env`. Ne jamais hardcoder les secrets.

**Exercice 33.5** - CLI avec argparse  
Crée une CLI avec `argparse`. Ajoute des arguments : `--verbose`, `--config fichier`, commandes (comme `python app.py run`, `python app.py test`).

**Exercice 33.6** - Click pour CLI  
Installe Click. Crée une CLI plus élégante : `@click.command()`, `@click.option()`, `@click.argument()`. Gère les sous-commandes avec `@click.group()`.

**Exercice 33.7** - Logging structuré  
Configure un système de logging professionnel avec plusieurs handlers (console, fichier), rotation des logs, formatage JSON pour parsing facile.

**Exercice 33.8** - Gestion d'erreurs globale  
Crée un gestionnaire d'exceptions global avec `sys.excepthook` ou un décorateur sur la fonction main. Log toutes les erreurs non gérées.

**Exercice 33.9** - Version et metadata  
Crée un fichier `__version__.py` avec la version. Documente le projet dans `README.md` : installation, usage, exemples. Ajoute un `CHANGELOG.md`.

**Exercice 33.10** - Makefile ou scripts  
Crée un `Makefile` ou des scripts bash/Python pour automatiser : `make install` (installe deps), `make test` (lance tests), `make lint` (vérifie code), `make run`.

---

### **Chapitre 34 — Publier un package**

**Exercice 34.1** - Setup.py basique  
Crée un `setup.py` simple avec `setuptools.setup()`. Remplis : name, version, author, description, packages, install_requires. Teste l'installation locale avec `pip install -e .`.

**Exercice 34.2** - Pyproject.toml moderne  
Crée un `pyproject.toml` (standard moderne). Configure : `[build-system]`, `[project]` avec métadonnées. Utilise `python -m build` pour builder.

**Exercice 34.3** - MANIFEST.in  
Crée un `MANIFEST.in` pour inclure des fichiers non-Python : README, LICENSE, fichiers de données. Vérifie qu'ils sont bien inclus dans le package distribué.

**Exercice 34.4** - Entry points  
Configure des entry points dans setup.py pour créer des commandes CLI installables : `entry_points={'console_scripts': ['monapp=monpackage.main:main']}`.

**Exercice 34.5** - Tests avant publication  
Vérifie ton package avec `twine check dist/*`. Teste l'installation dans un venv propre. Vérifie que toutes les dépendances sont déclarées.

**Exercice 34.6** - Versionning sémantique  
Documente ton système de versioning (semantic versioning : MAJOR.MINOR.PATCH). Crée un `CHANGELOG.md` avec les versions et changements.

**Exercice 34.7** - TestPyPI  
Crée un compte sur TestPyPI. Upload ton package : `twine upload --repository testpypi dist/*`. Teste l'installation depuis TestPyPI.

**Exercice 34.8** - Publication PyPI  
Upload sur PyPI réel : `twine upload dist/*`. Installe ton package publié : `pip install tonpackage`. Vérifie sur pypi.org.

**Exercice 34.9** - Documentation package  
Crée une documentation : docstrings complètes, README détaillé, exemples d'usage. Génère la doc avec Sphinx et héberge sur ReadTheDocs.

**Exercice 34.10** - Maintenance  
Planifie la maintenance : répondre aux issues GitHub, accepter pull requests, publier des nouvelles versions, supporter plusieurs versions de Python.

---

### **Chapitre 35 — CI/CD pour Python**

**Exercice 35.1** - GitHub Actions setup  
Crée un fichier `.github/workflows/test.yml`. Configure un workflow qui s'exécute sur push : checkout code, setup Python, install deps, run tests.

**Exercice 35.2** - Tests sur multiple Python  
Configure une matrice pour tester sur plusieurs versions de Python (3.8, 3.9, 3.10, 3.11, 3.12) et plusieurs OS (ubuntu, windows, macos).

**Exercice 35.3** - Linting automatique  
Ajoute une étape de linting dans CI : `flake8`, `pylint`, ou `ruff`. Le build échoue si le code n'est pas conforme.

**Exercice 35.4** - Black et isort  
Ajoute Black (formatter) et isort (tri imports) en CI. Configure pour vérifier que le code est formaté : `black --check .` et `isort --check-only .`.

**Exercice 35.5** - Coverage en CI  
Ajoute pytest-cov en CI. Upload le rapport de couverture vers Codecov ou Coveralls. Affiche le badge de couverture dans le README.

**Exercice 35.6** - Type checking  
Ajoute mypy en CI pour la vérification des types. Configure strictement ou progressivement. Le build échoue si les types sont incorrects.

**Exercice 35.7** - Security scanning  
Ajoute `bandit` (scan de sécurité) et `safety` (vérification de dépendances vulnérables) en CI. Alerte sur les problèmes de sécurité.

**Exercice 35.8** - Build et artifacts  
Configure CI pour builder ton package (`python -m build`). Sauvegarde les artifacts (wheels, sdist) pour les releases.

**Exercice 35.9** - Auto-release  
Configure un workflow qui publie automatiquement sur PyPI quand tu crées un tag Git : `git tag v1.0.0 && git push --tags`.

**Exercice 35.10** - Pipeline complet  
Crée un pipeline complet : lint -> test -> coverage -> security -> build -> (optionnel: deploy). Chaque étape doit passer pour continuer.

---

### **Chapitre 36 — Sécurité et bonnes pratiques pro**

**Exercice 36.1** - Gestion des secrets  
Ne jamais hardcoder de secrets. Utilise des variables d'environnement, `python-dotenv`, ou des gestionnaires de secrets (AWS Secrets Manager, Azure Key Vault).

**Exercice 36.2** - Validation d'entrées  
Crée une fonction qui valide toutes les entrées utilisateur. Utilise Pydantic pour valider les types et contraintes. Ne jamais faire confiance aux entrées.

**Exercice 36.3** - SQL Injection  
Démontre une injection SQL avec des requêtes non paramétrées. Corrige en utilisant des requêtes paramétrées ou un ORM. Teste la sécurité.

**Exercice 36.4** - Hashage de mots de passe  
Utilise `bcrypt` ou `argon2` pour hasher des mots de passe. Ne jamais stocker en clair. Implémente une fonction de login sécurisée.

**Exercice 36.5** - HTTPS et certificats  
Configure requests pour vérifier les certificats SSL. Gère les erreurs de certificat. Configure timeout pour éviter les blocages infinis.

**Exercice 36.6** - Type hints complets  
Ajoute des type hints partout : fonctions, méthodes, attributs de classe. Utilise `from typing import List, Dict, Optional`. Vérifie avec mypy.

**Exercice 36.7** - Principe du moindre privilège  
Dans ton code, limite les permissions : ouvre les fichiers en lecture seule si pas besoin d'écrire, limite les connexions réseau, sandboxe l'exécution de code.

**Exercice 36.8** - Audit de dépendances  
Utilise `pip-audit` ou `safety` pour scanner les dépendances vulnérables. Mets à jour régulièrement. Configure des alertes automatiques.

**Exercice 36.9** - Logging sécurisé  
Ne logue jamais de données sensibles (mots de passe, tokens). Sanitize les logs. Utilise des niveaux appropriés. Protège les fichiers de logs.

**Exercice 36.10** - Checklist sécurité  
Crée une checklist de sécurité pour tes projets : validation entrées, gestion secrets, HTTPS, hashage mots de passe, dépendances à jour, logs sécurisés, principe moindre privilège.

---

### **Chapitre 37 — Design Patterns**

**Exercice 37.1** - Singleton  
Implémente le pattern Singleton : une classe qui ne peut avoir qu'une seule instance. Utilise une variable de classe et `__new__`. Teste que deux instanciations retournent le même objet.

**Exercice 37.2** - Factory  
Crée une Factory qui crée différents types d'objets selon un paramètre. Exemple : `AnimalFactory.create('chien')` retourne un Chien, `.create('chat')` retourne un Chat.

**Exercice 37.3** - Abstract Factory  
Crée une Abstract Factory : une factory qui crée des familles d'objets liés. Exemple : `ModerneFactory` crée chaise moderne et table moderne, `AntiqueFactory` crée version antique.

**Exercice 37.4** - Builder  
Implémente le pattern Builder pour construire des objets complexes étape par étape. Exemple : `PizzaBuilder().add_cheese().add_tomato().add_pepperoni().build()`.

**Exercice 37.5** - Observer  
Crée le pattern Observer : un sujet notifie automatiquement tous ses observateurs quand son état change. Exemple : newsletter qui notifie tous les abonnés.

**Exercice 37.6** - Strategy  
Implémente Strategy : définir une famille d'algorithmes interchangeables. Exemple : classe `Calculatrice` qui peut utiliser différentes stratégies de calcul (addition, multiplication, etc.).

**Exercice 37.7** - Decorator pattern  
Différent du décorateur Python ! Pattern qui ajoute dynamiquement des responsabilités à un objet. Exemple : `Cafe` de base, puis `AvecLait(Cafe)`, puis `AvecSucre(AvecLait(Cafe))`.

**Exercice 37.8** - Adapter  
Crée un Adapter qui fait l'interface entre deux classes incompatibles. Transforme l'interface d'une classe pour qu'elle corresponde à ce qu'attend le client.

**Exercice 37.9** - Facade  
Implémente une Facade qui fournit une interface simplifiée à un système complexe. Cache la complexité derrière une interface unique et simple.

**Exercice 37.10** - Command  
Crée le pattern Command : encapsule une requête comme un objet. Permet de paramétrer des opérations, de les mettre en file d'attente, et de les annuler (undo).

---

### **Chapitre 38 — Performance et optimisation**

**Exercice 38.1** - Mesure avec time  
Utilise `time.time()` ou `time.perf_counter()` pour mesurer le temps d'exécution de code. Compare plusieurs implémentations d'un même algorithme.

**Exercice 38.2** - Timeit  
Utilise le module `timeit` pour mesurer précisément : `timeit.timeit('ma_fonction()', number=1000)`. Compare list comprehension vs boucle for.

**Exercice 38.3** - cProfile  
Profile ton code avec `python -m cProfile script.py`. Identifie les fonctions qui prennent le plus de temps. Utilise `pstats` pour analyser les résultats.

**Exercice 38.4** - line_profiler  
Installe line_profiler. Décore une fonction avec `@profile`. Exécute avec `kernprof -l -v script.py`. Identifie les lignes les plus lentes.

**Exercice 38.5** - Memory profiling  
Utilise `memory_profiler` pour suivre l'usage mémoire ligne par ligne. Identifie les fuites mémoire ou les structures gourmandes.

**Exercice 38.6** - Optimisation algorithme  
Prends un algorithme O(n²) (par exemple, tri à bulles). Optimise-le en O(n log n) (tri fusion ou rapide). Mesure la différence de performance sur grandes données.

**Exercice 38.7** - Structures de données  
Compare les performances : list vs deque pour insertions, list vs set pour recherche, dict vs list pour lookup. Choisis la bonne structure selon l'usage.

**Exercice 38.8** - Cache et memoization  
Utilise `@functools.lru_cache()` pour cacher les résultats de fonctions coûteuses (exemple : Fibonacci). Mesure l'amélioration de performance.

**Exercice 38.9** - Numpy vs Python pur  
Compare des calculs sur grandes listes : boucle Python vs opérations vectorisées numpy. Numpy est beaucoup plus rapide pour les opérations numériques.

**Exercice 38.10** - Optimisation complète  
Prends un programme lent. Profile, identifie les bottlenecks, optimise (meilleur algo, meilleure structure, cache, vectorisation). Documente les gains de performance obtenus.

---

### **Chapitre 39 — Documentation et qualité**

**Exercice 39.1** - Docstrings standards  
Écris des docstrings complètes format Google ou NumPy : description, Args, Returns, Raises, Examples. Utilise sur fonctions, classes et modules.

**Exercice 39.2** - Type hints dans docstrings  
Combine type hints et docstrings. Les type hints donnent les types, les docstrings expliquent le comportement et les contraintes.

**Exercice 39.3** - Sphinx setup  
Installe Sphinx. Initialise avec `sphinx-quickstart`. Configure `conf.py`. Génère la doc HTML avec `make html`. Ouvre `_build/html/index.html`.

**Exercice 39.4** - Autodoc Sphinx  
Configure l'extension `autodoc` de Sphinx pour générer automatiquement la doc depuis les docstrings. Utilise `.. automodule::`, `.. autoclass::`, `.. autofunction::`.

**Exercice 39.5** - MkDocs  
Alternative à Sphinx : installe MkDocs. Crée des fichiers Markdown dans `docs/`. Configure `mkdocs.yml`. Génère avec `mkdocs build` ou sers avec `mkdocs serve`.

**Exercice 39.6** - Flake8 linting  
Configure flake8 avec un fichier `.flake8`. Définis les règles (longueur ligne, imports inutilisés, etc.). Corrige tous les warnings. Intègre en pre-commit.

**Exercice 39.7** - Black formatting  
Applique Black sur tout ton code : `black .`. Configure un `pyproject.toml` pour personnaliser (longueur ligne, etc.). Intègre en pre-commit hook.

**Exercice 39.8** - Isort imports  
Utilise isort pour trier automatiquement les imports : `isort .`. Configure pour séparer stdlib, third-party, et local. Combine avec Black.

**Exercice 39.9** - Pre-commit hooks  
Installe pre-commit. Crée `.pre-commit-config.yaml` avec hooks : black, isort, flake8, mypy. À chaque commit, le code est vérifié automatiquement.

**Exercice 39.10** - Code review checklist  
Crée une checklist de review : code lisible, nommage clair, fonctions courtes, tests, docstrings, type hints, pas de code dupliqué, gestion d'erreurs, performance acceptable.

---

### **Chapitre 40 — Python et DevOps**

**Exercice 40.1** - Script de backup  
Crée un script qui sauvegarde automatiquement un dossier : copie vers un autre emplacement avec timestamp, compression en zip, suppression des anciennes sauvegardes.

**Exercice 40.2** - Monitoring logs  
Crée un script qui surveille un fichier de log en temps réel (tail -f), détecte les erreurs, et envoie une alerte (email, Slack, etc.).

**Exercice 40.3** - Health check  
Crée un script qui vérifie la santé d'une application : teste les endpoints, vérifie la connexion DB, vérifie l'espace disque, alerte si problème.

**Exercice 40.4** - Déploiement automatisé  
Crée un script de déploiement : pull code depuis git, install dépendances, run migrations, restart service. Rends-le idempotent (peut s'exécuter plusieurs fois sans problème).

**Exercice 40.5** - Gestion de services  
Crée un script qui gère des services système : start, stop, restart, status. Utilise `subprocess` pour interagir avec systemd ou d'autres gestionnaires de services.

**Exercice 40.6** - Docker avec Python  
Crée un Dockerfile pour ton application Python. Optimise les layers, utilise alpine pour taille réduite, multi-stage build. Build et run : `docker build -t monapp .`.

**Exercice 40.7** - Fabric pour déploiement  
Installe Fabric. Crée des tâches de déploiement : connexion SSH, transfert fichiers, exécution commandes distantes. Déploie sur plusieurs serveurs en parallèle.

**Exercice 40.8** - Ansible playbook  
Crée un playbook Ansible qui configure un serveur : installe Python, dépendances système, clone repo, configure service. Execute avec `ansible-playbook`.

**Exercice 40.9** - Infrastructure as Code  
Utilise `boto3` (AWS SDK) pour créer/gérer des ressources cloud par code : créer EC2, S3 bucket, RDS. Documente l'infrastructure en code.

**Exercice 40.10** - CI/CD pipeline complet  
Crée un pipeline DevOps complet : commit -> tests auto -> build Docker -> push registry -> deploy staging -> tests intégration -> deploy production. Tout automatisé.

---

### **Chapitre 41 — Python et API externes**

**Exercice 41.1** - GitHub API  
Utilise l'API GitHub pour : lister tes repos, créer un issue, lister les commits d'un repo. Authentification avec token personnel.

**Exercice 41.2** - Twitter/X API  
Connecte-toi à l'API Twitter. Récupère les derniers tweets d'un utilisateur, recherche des tweets par hashtag, poste un tweet (avec prudence !).

**Exercice 41.3** - OpenWeatherMap API  
Crée une app météo : demande une ville, récupère les données météo actuelles et prévisions, affiche température, humidité, description joliment formatée.

**Exercice 41.4** - Stripe API  
Explore l'API Stripe (mode test). Crée un customer, crée un payment intent, liste les transactions. Ne jamais exposer les clés secrètes.

**Exercice 41.5** - Google Maps API  
Utilise l'API Google Maps pour : géocoder une adresse (obtenir lat/lon), reverse geocode (obtenir adresse depuis coordonnées), calculer distance entre deux points.

**Exercice 41.6** - SendGrid Email API  
Configure SendGrid. Crée un script qui envoie des emails : simple texte, HTML, avec pièces jointes, emails en masse. Gère les erreurs d'envoi.

**Exercice 41.7** - Slack API  
Crée un bot Slack simple : écoute des messages, répond automatiquement, poste dans un channel, envoie des notifications d'événements de ton app.

**Exercice 41.8** - OpenAI API  
Utilise l'API OpenAI (GPT). Crée un chatbot simple, génère du texte, fais de la complétion de code. Gère les tokens et coûts.

**Exercice 41.9** - Pagination d'API  
Beaucoup d'APIs paginent les résultats. Crée une fonction générique qui récupère TOUTES les pages automatiquement en suivant les liens next/cursors.

**Exercice 41.10** - Rate limiting  
Implémente un rate limiter pour ne pas dépasser les limites d'API : attente entre requêtes, backoff exponentiel si erreur 429, queue de requêtes.

---

### **Chapitre 42 — Python et Cloud**

**Exercice 42.1** - AWS Lambda basique  
Crée une fonction Lambda simple en Python. Deploy avec AWS Console ou CLI. Teste l'exécution. Observe les logs dans CloudWatch.

**Exercice 42.2** - Lambda avec trigger  
Configure un trigger pour ta Lambda : S3 (nouveau fichier), API Gateway (requête HTTP), CloudWatch Events (cron). Teste le déclenchement automatique.

**Exercice 42.3** - Boto3 S3  
Utilise boto3 pour interagir avec S3 : créer bucket, upload fichiers, download, lister objets, supprimer, générer presigned URLs.

**Exercice 42.4** - Lambda layers  
Crée un layer Lambda avec tes dépendances (requests, pandas, etc.). Attache-le à ta fonction Lambda. Réduit la taille de ton package de déploiement.

**Exercice 42.5** - Azure Functions  
Crée une Azure Function en Python. Configure le trigger (HTTP, Timer, Blob). Deploy avec Azure CLI. Compare avec AWS Lambda.

**Exercice 42.6** - Google Cloud Functions  
Crée une Cloud Function sur GCP. Trigger HTTP ou Pub/Sub. Deploy avec gcloud CLI. Explore Cloud Run pour conteneurs.

**Exercice 42.7** - DynamoDB avec boto3  
Utilise DynamoDB : crée une table, insert items, query par clé de partition, scan avec filtre, update item, delete item. Comprends le modèle NoSQL.

**Exercice 42.8** - Secrets Manager  
Stocke des secrets dans AWS Secrets Manager ou Azure Key Vault. Récupère-les dans ton code. Ne jamais hardcoder les credentials.

**Exercice 42.9** - CloudWatch logging  
Configure logging pour envoyer vers CloudWatch. Crée des métriques custom. Configure des alarmes qui notifient si seuils dépassés.

**Exercice 42.10** - Architecture serverless complète  
Crée une API serverless complète : API Gateway -> Lambda (business logic) -> DynamoDB (storage) + S3 (fichiers) + SQS (async tasks). Tout infrastructure as code.

---

### **Chapitre 43 — Python et Sécurité (DevSecOps)**

**Exercice 43.1** - Bandit scan  
Installe Bandit. Scan ton code : `bandit -r .`. Analyse les vulnérabilités détectées (hardcoded passwords, SQL injection, etc.). Corrige-les.

**Exercice 43.2** - Safety check  
Utilise Safety pour vérifier les dépendances vulnérables : `safety check`. Identifie les CVEs dans tes packages. Mets à jour les versions affectées.

**Exercice 43.3** - Secrets scanning  
Utilise detect-secrets ou truffleHog pour scanner le repo à la recherche de secrets commités. Configure pre-commit hook pour bloquer les commits avec secrets.

**Exercice 43.4** - OWASP Top 10  
Étudie OWASP Top 10. Pour chaque vulnérabilité, crée un exemple vulnerable en Python, puis la version sécurisée. Documente les bonnes pratiques.

**Exercice 43.5** - Chiffrement de données  
Utilise `cryptography` pour chiffrer/déchiffrer des données sensibles. Implémente Fernet (chiffrement symétrique). Gère les clés de façon sécurisée.

**Exercice 43.6** - JWT tokens  
Implémente l'authentification JWT : génération de token lors du login, validation du token, refresh token, révocation. Utilise `PyJWT`.

**Exercice 43.7** - Input validation  
Crée des validateurs d'entrées robustes avec Pydantic. Valide types, formats (email, URL), longueurs, patterns regex. Rejette tout ce qui n'est pas explicitement valide.

**Exercice 43.8** - CSRF protection  
Implémente la protection CSRF dans une app web Flask/Django. Génère et valide des tokens CSRF pour tous les formulaires POST.

**Exercice 43.9** - Security headers  
Configure les headers de sécurité HTTP : Content-Security-Policy, X-Frame-Options, Strict-Transport-Security. Utilise des bibliothèques comme flask-talisman.

**Exercice 43.10** - Audit de sécurité complet  
Fais un audit complet d'une application : scan vulnérabilités code, dépendances, configuration, secrets, injection, auth, logs. Produis un rapport avec remédiation.

---

### **Chapitre 44 — Python pour la cybersécurité**

**Exercice 44.1** - Port scanner  
Crée un scanner de ports avec `socket`. Teste quels ports sont ouverts sur une machine (TCP SYN scan basique). Ajoute le threading pour scanner plus vite.

**Exercice 44.2** - Network sniffer  
Utilise `scapy` pour sniffer les paquets réseau. Capture et analyse : adresses IP source/destination, ports, protocoles. Filtre par type de paquet.

**Exercice 44.3** - Password cracking  
Crée un script de brute force pour tester des mots de passe contre un hash. Utilise bcrypt ou hashlib. Teste avec wordlist. Comprends pourquoi le hashing fort est important.

**Exercice 44.4** - Log analyzer  
Crée un analyseur de logs (Apache, Nginx, SSH). Détecte les tentatives de bruteforce, scans, IP suspectes. Génère un rapport d'incidents.

**Exercice 44.5** - Subdomain enumeration  
Crée un outil qui énumère les sous-domaines d'un domaine. Utilise DNS queries, bruteforce avec wordlist, certificate transparency logs.

**Exercice 44.6** - Keylogger (éthique)  
Crée un keylogger éducatif avec `pynput`. ATTENTION : usage strictement éducatif sur ta propre machine. Comprends comment se protéger contre.

**Exercice 44.7** - MAC address spoofing  
Crée un script qui change l'adresse MAC d'une interface réseau (Linux). Utilise subprocess pour exécuter les commandes système nécessaires.

**Exercice 44.8** - Network packet manipulation  
Utilise Scapy pour créer et envoyer des paquets personnalisés : ARP, TCP, UDP. Crée un simple packet injector. Comprends les risques.

**Exercice 44.9** - Malware analysis  
Crée un sandbox simple qui exécute du code suspect dans un environnement isolé. Monitore : appels système, connexions réseau, modifications fichiers.

**Exercice 44.10** - Penetration testing tool  
Combine plusieurs outils créés : recon (scan ports, subdomains), exploitation (tester vulnérabilités communes), post-exploitation (collecte d'infos). Framework éthique complet.

---

### **Chapitre 45 — Python pour l'automatisation système**

**Exercice 45.1** - Monitoring système  
Utilise `psutil` pour monitorer : CPU, RAM, disque, réseau, processus. Affiche en temps réel ou log dans fichier. Alerte si seuils dépassés.

**Exercice 45.2** - File organizer  
Crée un script qui organise automatiquement un dossier : trie les fichiers par extension dans des sous-dossiers, renomme selon pattern, supprime les doublons.

**Exercice 45.3** - Bulk rename  
Crée un outil de renommage en masse : regex pour pattern matching, prévisualisation avant application, undo possible, gestion des conflits de noms.

**Exercice 45.4** - Scheduled tasks  
Crée des tâches planifiées avec `schedule` : backup quotidien, nettoyage hebdomadaire, rapport mensuel. Alternative : utilise cron (Linux) ou Task Scheduler (Windows) depuis Python.

**Exercice 45.5** - SSH automation  
Utilise `paramiko` pour automatiser SSH : connexion à serveur distant, exécution de commandes, transfert de fichiers (SFTP), gestion de plusieurs serveurs.

**Exercice 45.6** - Process management  
Crée un gestionnaire de processus : lance/arrête des programmes, redémarre si crash, monitore l'usage ressources, logs de chaque processus.

**Exercice 45.7** - Disk space cleaner  
Crée un nettoyeur intelligent : trouve les gros fichiers, fichiers temporaires, doublons (hash MD5), vieux fichiers. Demande confirmation avant suppression.

**Exercice 45.8** - System health report  
Génère un rapport HTML de santé système : uptime, charge CPU/RAM, espace disque, top processus, services en cours, connexions réseau actives.

**Exercice 45.9** - Automated testing suite  
Crée une suite qui teste automatiquement une app : lance l'app, effectue des actions, vérifie les résultats, capture screenshots si erreur, génère rapport.

**Exercice 45.10** - Complete automation framework  
Combine tout : monitoring continu, backups automatiques, nettoyage, alertes, rapports. Dashboard web pour visualiser. Tout configurable par fichier config.

---

### **Chapitre 46 — Python pour le scraping et les bots**

**Exercice 46.1** - Requests + BeautifulSoup  
Scrape une page web simple : récupère le HTML avec requests, parse avec BeautifulSoup, extrait titres/liens/textes. Respecte robots.txt.

**Exercice 46.2** - CSS selectors  
Utilise les sélecteurs CSS dans BeautifulSoup : `.select('.classe')`, `.select('#id')`, `.select('div > p')`. Extrait des données spécifiques d'une page complexe.

**Exercice 46.3** - Scraping pagination  
Scrape un site avec pagination : détecte le lien "Next", navigue automatiquement toutes les pages, collecte toutes les données, sauvegarde en CSV.

**Exercice 46.4** - Selenium basique  
Installe Selenium et chromedriver. Automatise le navigateur : ouvre une page, clique sur boutons, remplit formulaires, soumet, récupère résultats.

**Exercice 46.5** - Handling JavaScript  
Scrape un site avec contenu chargé en JavaScript (impossible avec requests). Utilise Selenium pour attendre le chargement, puis extraire les données.

**Exercice 46.6** - Scrapy spider  
Installe Scrapy. Crée un spider : définis start_urls, parse method, items, suivis de liens. Lance avec `scrapy crawl`. Plus puissant que requests+BeautifulSoup.

**Exercice 46.7** - Bot Telegram  
Crée un bot Telegram avec `python-telegram-bot`. Répond aux commandes, envoie messages/images, gère des conversations, stocke état utilisateur.

**Exercice 46.8** - Bot Discord  
Crée un bot Discord avec `discord.py`. Répond à des commandes, modère salon, envoie embeds, réagit à des événements, gère permissions.

**Exercice 46.9** - Anti-scraping bypass  
Gère les protections anti-scraping : user-agent rotation, proxies, delays aléatoires, session persistence, cookies, gestion des CAPTCHAs (manuels ou services).

**Exercice 46.10** - Complete scraping project  
Projet complet : scrape un site e-commerce (produits, prix, avis), stocke en DB, détecte changements de prix, envoie alertes, dashboard de visualisation.

---

### **Chapitre 47 — Python pour les bases de données**

**Exercice 47.1** - SQLite basique  
Utilise `sqlite3`. Crée une DB, une table, insère des données avec INSERT, récupère avec SELECT, update, delete. Comprends les requêtes SQL de base.

**Exercice 47.2** - Connexion paramétrisée  
Utilise des requêtes paramétrées pour éviter SQL injection : `cursor.execute("SELECT * FROM users WHERE name = ?", (name,))`. Ne jamais concaténer directement.

**Exercice 47.3** - Context manager DB  
Utilise `with` pour gérer les connexions DB : commit automatique si succès, rollback si erreur. Crée ton propre context manager pour DB.

**Exercice 47.4** - PostgreSQL avec psycopg2  
Installe psycopg2. Connecte-toi à PostgreSQL, exécute des requêtes. Compare avec SQLite : types de données, performances, fonctionnalités avancées.

**Exercice 47.5** - ORM SQLAlchemy basique  
Installe SQLAlchemy. Définis des modèles avec classes. Utilise l'ORM pour CRUD : `session.add()`, `.query()`, `.filter()`, `.update()`, `.delete()`.

**Exercice 47.6** - Relations SQLAlchemy  
Crée des modèles avec relations : One-to-Many (Auteur -> Livres), Many-to-Many (Étudiants <-> Cours). Navigue les relations : `auteur.livres`, `livre.auteur`.

**Exercice 47.7** - Migrations Alembic  
Utilise Alembic avec SQLAlchemy. Initialise, crée migration auto depuis modèles, applique migrations. Gère les versions de schema de DB.

**Exercice 47.8** - Transactions et rollback  
Implémente des transactions : commence transaction, effectue plusieurs opérations, commit si tout ok, rollback si erreur. Garantis la cohérence des données.

**Exercice 47.9** - Query optimization  
Apprends à optimiser : utilise indexes, évite N+1 queries (eager loading), utilise joinedload/subqueryload, profile avec `EXPLAIN`. Mesure les performances.

**Exercice 47.10** - Database abstraction layer  
Crée une couche d'abstraction qui fonctionne avec SQLite, PostgreSQL, MySQL. Utilise SQLAlchemy pour la portabilité. Teste la même app sur différentes DBs.

---

### **Chapitre 48 — Python et APIs GraphQL / REST**

**Exercice 48.1** - REST API complète Flask  
Crée une API REST avec Flask : endpoints CRUD pour une ressource (GET, POST, PUT, DELETE). Retourne JSON, gère les codes de statut HTTP appropriés.

**Exercice 48.2** - Flask-RESTful  
Utilise Flask-RESTful pour simplifier. Crée des Resources avec méthodes get/post/put/delete. Utilise reqparse pour valider les entrées.

**Exercice 48.3** - FastAPI CRUD  
Crée la même API avec FastAPI. Utilise Pydantic pour validation auto, génération auto de docs (Swagger UI). Compare avec Flask : plus moderne, plus rapide.

**Exercice 48.4** - Authentication API  
Implémente l'authentification dans ton API : endpoint /login (retourne JWT), middleware qui valide le token sur endpoints protégés, /refresh pour renouveler.

**Exercice 48.5** - Pagination et filtering  
Ajoute pagination : `GET /items?page=2&limit=20`. Ajoute filtrage : `?status=active&sort=name`. Retourne métadonnées : total items, pages, etc.

**Exercice 48.6** - API documentation  
Génère documentation API automatiquement : Swagger/OpenAPI avec FastAPI, ou flask-swagger. Documente chaque endpoint : paramètres, responses, exemples.

**Exercice 48.7** - GraphQL avec Graphene  
Installe Graphene. Crée un schema GraphQL avec types, queries, mutations. Compare avec REST : un seul endpoint, client demande exactement ce qu'il veut.

**Exercice 48.8** - GraphQL resolvers  
Implémente des resolvers complexes : avec arguments, avec connexion DB, résolution de relations (N+1 problem), dataloaders pour batching.

**Exercice 48.9** - API versioning  
Implémente le versioning d'API : par URL (`/api/v1/`, `/api/v2/`), par header, ou par paramètre. Gère la compatibilité entre versions.

**Exercice 48.10** - API complète production-ready  
Crée une API complète : auth, CRUD, pagination, filtering, validation, error handling, logging, rate limiting, CORS, tests, documentation, deployment.

---

### **Chapitre 49 — Python et data pipelines**

**Exercice 49.1** - ETL simple  
Crée un pipeline ETL basique : Extract (lire CSV), Transform (nettoyer/transformer données), Load (écrire en DB). Log chaque étape.

**Exercice 49.2** - Data validation  
Ajoute validation des données : types corrects, valeurs dans plages attendues, pas de doublons, champs obligatoires présents. Rejette ou corrige les lignes invalides.

**Exercice 49.3** - Pandas pipeline  
Crée un pipeline Pandas : chaîne plusieurs transformations, applique fonctions custom, gère les missing values, agrège, pivote. Sortie : données propres et structurées.

**Exercice 49.4** - Incremental loading  
Implémente le chargement incrémental : ne charge que les nouvelles données depuis le dernier run. Utilise timestamps ou IDs pour identifier les nouveaux records.

**Exercice 49.5** - Data quality checks  
Implémente des checks de qualité : complétude, unicité, validité, cohérence. Génère un rapport de qualité. Alerte si qualité se dégrade.

**Exercice 49.6** - Apache Airflow DAG  
Installe Airflow. Crée un DAG avec plusieurs tasks : extract -> validate -> transform -> load. Définis dépendances, scheduling, retry logic.

**Exercice 49.7** - Parallel processing  
Optimise ton pipeline pour traiter en parallèle : multiprocessing pour CPU-bound, threading pour I/O-bound, ou concurrent.futures. Mesure l'amélioration.

**Exercice 49.8** - Error handling pipeline  
Gère robustement les erreurs : retry avec backoff, dead letter queue pour records en échec, logging détaillé, alertes, continuation même si certains records échouent.

**Exercice 49.9** - Data lineage  
Implémente le tracking de data lineage : d'où viennent les données, quelles transformations appliquées, où elles vont. Metadata management.

**Exercice 49.10** - Production pipeline  
Pipeline complet production : scheduling (cron/Airflow), monitoring, alertes, logs centralisés, idempotence, tests, documentation, rollback capability.

---

### **Chapitre 50 — Python et Intelligence Artificielle**

**Exercice 50.1** - TensorFlow basics  
Installe TensorFlow. Crée un réseau de neurones simple pour classification (MNIST digits). Compile, entraîne, évalue. Comprends les concepts de base.

**Exercice 50.2** - PyTorch basics  
Installe PyTorch. Crée le même réseau en PyTorch. Compare avec TensorFlow : syntaxe, performance, facilité d'utilisation. PyTorch est plus pythonique.

**Exercice 50.3** - CNN pour images  
Crée un Convolutional Neural Network pour classifier des images. Utilise couches Conv2D, MaxPooling, Flatten, Dense. Entraîne sur dataset d'images.

**Exercice 50.4** - Transfer learning  
Utilise un modèle pré-entraîné (ResNet, VGG) comme base. Freeze les couches, ajoute tes couches de classification. Fine-tune sur ton dataset spécifique.

**Exercice 50.5** - NLP avec transformers  
Utilise Hugging Face transformers. Charge un modèle pré-entraîné (BERT, GPT). Fais du sentiment analysis, text classification, ou generation.

**Exercice 50.6** - OpenAI API integration  
Intègre l'API OpenAI dans une app. Crée un chatbot, un générateur de contenu, un assistant de code. Gère les prompts, tokens, coûts.

**Exercice 50.7** - Fine-tuning models  
Fine-tune un modèle pre-trained sur tes propres données. Prépare dataset au bon format, configure hyperparamètres, entraîne, évalue, sauvegarde.

**Exercice 50.8** - RAG system  
Implémente Retrieval-Augmented Generation : vectorise tes documents, stocke embeddings, requête similaire, récupère contexte pertinent, génère réponse avec LLM.

**Exercice 50.9** - Model deployment  
Deploy un modèle ML : sauvegarde modèle, crée API Flask/FastAPI qui sert les prédictions, containerise avec Docker, déploie sur cloud. Gère le versioning.

**Exercice 50.10** - MLOps pipeline  
Pipeline MLOps complet : data collection -> preprocessing -> training -> evaluation -> deployment -> monitoring. Track experiments (MLflow), version models, A/B testing.

---

### **Chapitre 51 — Python avancé : introspection et reflection**

**Exercice 51.1** - Dir et help  
Utilise `dir(objet)` pour lister tous attributs/méthodes. Utilise `help(fonction)` pour la documentation. Explore des objets inconnus dynamiquement.

**Exercice 51.2** - Inspect module  
Utilise `inspect.getmembers()`, `.getfullargspec()`, `.getsourcelines()`, `.getfile()`. Crée un outil qui analyse automatiquement un module et génère documentation.

**Exercice 51.3** - Sys module introspection  
Explore `sys.modules` (modules importés), `sys.path` (chemins de recherche), `sys.getsizeof()` (taille mémoire objets). Crée un profiler de mémoire.

**Exercice 51.4** - Importlib dynamique  
Utilise `importlib.import_module('nom_module')` pour importer dynamiquement. Crée un système de plugins : scanne un dossier, importe tous les modules Python trouvés.

**Exercice 51.5** - Frame inspection  
Utilise `inspect.currentframe()`, `.getouterframes()` pour inspecter la stack d'appels. Crée un debugger custom qui affiche la trace complète avec variables locales.

**Exercice 51.6** - Code objects  
Explore les code objects : `fonction.__code__`. Accède à `.co_varnames`, `.co_argcount`, `.co_code`. Comprends comment Python exécute le bytecode.

**Exercice 51.7** - Abstract Syntax Tree  
Utilise `ast` module. Parse du code Python en AST, traverse l'arbre, modifie-le, recompile. Crée un outil qui analyse le code (complexity, style, etc.).

**Exercice 51.8** - Monkey patching  
Modifie dynamiquement des classes/modules existants au runtime. Change une méthode d'une classe tierce. Comprends les risques et cas d'usage légitimes.

**Exercice 51.9** - Reflection complète  
Crée un système qui génère automatiquement des tests unitaires en inspectant les fonctions : détecte paramètres, types, génère cas de test, exécute, vérifie.

**Exercice 51.10** - Meta-framework  
Crée un mini-framework qui utilise introspection pour automatiser : auto-discovery de routes (web), auto-registration de plugins, auto-wiring de dépendances (DI).

---

### **Chapitre 52 — Clôture : les clés pour devenir un expert Python**

**Exercice 52.1** - Lire du code open source  
Clone un projet open source Python populaire (requests, flask, django). Lis le code, comprends l'architecture, les patterns utilisés. Contribue avec une petite PR.

**Exercice 52.2** - Code review practice  
Fais du code review sur GitHub. Cherche des PRs dans des projets Python, analyse le code, suggère améliorations, apprends des feedbacks.

**Exercice 52.3** - Refactoring project  
Prends un vieux projet à toi. Refactorise complètement : meilleure structure, design patterns, tests, documentation, type hints, CI/CD. Compare avant/après.

**Exercice 52.4** - Performance challenge  
Résous un problème de performance complexe : profile, identifie bottlenecks, optimise algorithme ET implémentation, mesure gains. Documente le processus.

**Exercice 52.5** - Contribution open source  
Contribue réellement à un projet open source : fix un bug, ajoute une feature, améliore la doc. Gère le processus complet : fork, branch, commit, PR, review.

**Exercice 52.6** - Teaching/Mentoring  
Enseigne Python à quelqu'un. Crée un tutoriel, enregistre une vidéo, réponds à des questions sur Stack Overflow. Enseigner c'est apprendre deux fois.

**Exercice 52.7** - Technical blog  
Écris un article technique sur un sujet Python avancé que tu maîtrises. Explique clairement, avec exemples. Publie sur Medium/Dev.to.

**Exercice 52.8** - Build a library  
Crée une bibliothèque Python réutilisable qui résout un problème réel. Tests complets, documentation, publie sur PyPI, maintiens (gère issues, PRs).

**Exercice 52.9** - System design  
Conçois l'architecture d'un système complexe en Python : microservices, messaging, caching, scaling. Documente les décisions, trade-offs, alternatives.

**Exercice 52.10** - Portfolio masterpiece  
Crée un projet portfolio qui démontre TOUTE ton expertise : architecture propre, tests, CI/CD, documentation, performance, sécurité, déploiement cloud, monitoring. Ton chef-d'œuvre.

---

## [OBJECTIF] FÉLICITATIONS !

Tu as maintenant **520 exercices progressifs** qui couvrent **TOUT Python**, du débutant absolu à l'expert professionnel.

### [LISTE] Conseils pour progresser efficacement :

1. **Fais les exercices dans l'ordre** - Chaque chapitre construit sur les précédents
2. **Ne saute pas d'exercices** - Chacun enseigne quelque chose d'important
3. **Code réellement** - Ne te contente pas de lire, tape le code !
4. **Expérimente** - Modifie les exercices, teste des variations
5. **Debug tes erreurs** - Les erreurs sont tes meilleures enseignantes
6. **Reviens aux bases** - Même expert, révise régulièrement les fondamentaux
7. **Partage ton code** - GitHub, code review, feedback des autres
8. **Construis des projets** - Applique ce que tu apprends dans des projets réels

### [RAPIDE] Prochaines étapes :

- Commence par le Chapitre 1, Exercice 1
- Avance à ton rythme (1-5 exercices par jour selon ton temps)
- Garde une trace de ta progression
- Crée un dossier pour chaque chapitre
- Sauvegarde tous tes codes sur GitHub
- N'hésite pas à demander de l'aide sur les forums Python

### [DOCS] Ressources complémentaires recommandées :

**Documentation officielle :**

- docs.python.org - Documentation Python officielle
- realpython.com - Tutoriels de qualité
- stackoverflow.com - Pour les questions

**Pratique :**

- leetcode.com - Algorithmes et structures de données
- hackerrank.com - Défis de programmation
- codewars.com - Katas Python
- exercism.org - Exercices avec mentorat

**Communauté :**

- r/learnpython - Reddit pour débutants
- python.org/community - Communauté officielle
- discord.gg/python - Serveur Discord Python

---

## [GUIDE] INDEX RAPIDE DES EXERCICES PAR THÈME

### [OBJECTIF] DÉBUTANT (Chapitres 1-7)

- **Chapitre 1-3** : Bases absolues (print, variables, strings)
- **Chapitre 4-5** : Structures de données (listes, dictionnaires)
- **Chapitre 6-7** : Logique (conditions, boucles, fonctions)

### [PRO] INTERMÉDIAIRE (Chapitres 8-20)

- **Chapitre 8-10** : Modules, fichiers, exceptions
- **Chapitre 11-12** : Programmation fonctionnelle
- **Chapitre 13-16** : POO complète
- **Chapitre 17-20** : Outils de développement

### [WEB] SPÉCIALISATIONS (Chapitres 21-26)

- **Chapitre 21-23** : Développement Web
- **Chapitre 24-26** : Data Science et ML

### [RAPIDE] AVANCÉ (Chapitres 27-32)

- **Chapitre 27-29** : Concepts avancés Python
- **Chapitre 30-31** : Programmation concurrente
- **Chapitre 32** : Métaprogrammation

### [PERSONNE][CODE] EXPERT (Chapitres 33-52)

- **Chapitre 33-36** : Projets professionnels
- **Chapitre 37-39** : Qualité et architecture
- **Chapitre 40-42** : DevOps et Cloud
- **Chapitre 43-44** : Sécurité et cybersécurité
- **Chapitre 45-46** : Automatisation et bots
- **Chapitre 47-50** : Bases de données et IA
- **Chapitre 51-52** : Maîtrise ultime

---

## [COURS] PARCOURS RECOMMANDÉS PAR OBJECTIF

### [PERSONNE][COURS] Pour devenir Développeur Web Python :

**Ordre prioritaire :** 1-20 (bases) -> 21-23 (web) -> 33-36 (projet pro) -> 47-48 (DB et API)

### [GRAPHIQUE] Pour devenir Data Scientist :

**Ordre prioritaire :** 1-20 (bases) -> 24-26 (data/ML) -> 47 (DB) -> 49-50 (pipelines et IA)

### [SECURISE] Pour devenir Expert Cybersécurité :

**Ordre prioritaire :** 1-20 (bases) -> 30-31 (concurrence) -> 36 (sécurité) -> 43-44 (cybersec) -> 45 (automatisation)

### [BOT] Pour devenir Ingénieur DevOps :

**Ordre prioritaire :** 1-20 (bases) -> 33-35 (structure/CI-CD) -> 40-42 (DevOps/Cloud) -> 45 (automatisation)

### [LOGIQUE] Pour devenir Expert IA/ML :

**Ordre prioritaire :** 1-20 (bases) -> 24-26 (ML basique) -> 47 (DB) -> 50 (IA avancée) -> 49 (pipelines)

### [OUTILS] Pour devenir Développeur Fullstack Python :

**Ordre prioritaire :** 1-26 (tout) -> 33-36 (projet pro) -> 47-48 (DB/API) -> 40-42 (déploiement)

---

## [RAPIDE] CHALLENGES BONUS

### Challenge 1 - Marathon 30 jours

Fais un exercice de chaque chapitre pendant 30 jours consécutifs. Documente ton parcours sur un blog ou GitHub.

### Challenge 2 - Projet intégrateur

Crée UN projet qui utilise des concepts de 10 chapitres différents minimum. Exemple : app web + ML + DB + API + tests + CI/CD.

### Challenge 3 - Mentor challenge

Aide 5 personnes différentes à résoudre des problèmes Python sur des forums. Enseigner = apprendre profondément.

### Challenge 4 - Speed coding

Prends 10 exercices aléatoires. Chronomètre-toi. Essaie de réduire ton temps en les refaisant une semaine plus tard.

### Challenge 5 - Code golf

Reprends 5 exercices. Réécris-les avec le moins de lignes/caractères possible TOUT EN gardant la lisibilité.

### Challenge 6 - Legacy refactoring

Reprends ton tout premier exercice après 6 mois. Refactorise-le avec tes nouvelles connaissances. Compare les versions.

### Challenge 7 - Library deep dive

Choisis une bibliothèque Python populaire. Fais TOUS les exercices qui l'utilisent. Deviens expert de cette lib.

### Challenge 8 - Multi-language

Après avoir fait des exercices en Python, refais-les dans un autre langage (JavaScript, Go, Rust). Compare les paradigmes.

### Challenge 9 - Performance competition

Prends un exercice d'algorithme. Optimise-le au maximum. Compare avec d'autres développeurs. Qui a la solution la plus rapide ?

### Challenge 10 - Contribution marathon

Contribue à 10 projets open source différents en 30 jours. Fixes de bugs, nouvelles features, documentation.

---

## [TROPHEE] SYSTÈME DE PROGRESSION

### [3e] Niveau Bronze (0-10% - Chapitres 1-5)

**Titre :** Apprenti Python  
**Compétences :** Bases du langage  
**Projet type :** Calculatrice, jeu de devinettes

### [2e] Niveau Argent (10-30% - Chapitres 6-12)

**Titre :** Développeur Python Junior  
**Compétences :** Logique et structures avancées  
**Projet type :** Gestionnaire de tâches, analyseur de texte

### [1er] Niveau Or (30-50% - Chapitres 13-23)

**Titre :** Développeur Python Confirmé  
**Compétences :** POO, Web, Data  
**Projet type :** API REST, app web complète, analyse de données

### [GEM_STONE] Niveau Platine (50-70% - Chapitres 24-36)

**Titre :** Développeur Python Senior  
**Compétences :** Spécialisations, qualité code  
**Projet type :** Système ML, architecture microservices

### [CROWN] Niveau Master (70-90% - Chapitres 37-48)

**Titre :** Expert Python  
**Compétences :** Architecture, DevOps, Sécurité  
**Projet type :** Plateforme complète, framework custom

### * Niveau Grand Master (90-100% - Chapitres 49-52)

**Titre :** Python Guru  
**Compétences :** Maîtrise totale, contribution communauté  
**Projet type :** Projets open source majeurs, innovation

---

## [OBJECTIF] CHECKLIST DE VALIDATION PAR CHAPITRE

Pour chaque chapitre, tu peux te considérer "validé" si :

[OK] Tu as complété les 10 exercices  
[OK] Tu comprends POURQUOI ton code fonctionne  
[OK] Tu peux expliquer les concepts à quelqu'un d'autre  
[OK] Tu as expérimenté au-delà des exercices  
[OK] Tu as documenté ton code proprement  
[OK] Tu as testé des cas limites  
[OK] Tu peux refaire les exercices sans regarder les solutions  
[OK] Tu as créé au moins une variation personnelle

---

## [NOTE] TEMPLATE DE TRACKING

Crée un fichier `progression.md` dans ton repo :

```markdown
# Ma Progression Python - De Débutant à Expert

**Date de début :** [DATE]  
**Objectif :** [Devenir expert Python]  
**Rythme prévu :** [X exercices/jour]

## Statistiques

- Chapitres complétés : X/52
- Exercices complétés : X/520
- Niveau actuel : [Bronze/Argent/Or/Platine/Master/Grand Master]
- Jours consécutifs : X

## Journal de progression

### Semaine 1

- [Date] Chapitre 1 - Exercices 1-10 [OK]
  - Apprentissages clés : ...
  - Difficultés rencontrées : ...
  - Temps total : Xh

### Semaine 2

- [Date] Chapitre 2 - Exercices 1-5 [OK]
  - ...

## Projets personnels inspirés des exercices

1. [Nom du projet] - Utilise concepts des chapitres X, Y, Z

## Questions à approfondir

- [ ] Question 1
- [ ] Question 2

## Ressources utiles découvertes

- [Lien] - Description
```

---

## * CONSEILS DE PYTHONISTAS EXPERTS

### Sur l'apprentissage :

> "Le meilleur moment pour commencer était hier. Le deuxième meilleur moment est maintenant."

> "Ne cherche pas à tout mémoriser. Apprends à chercher efficacement et à comprendre."

> "Chaque erreur est une opportunité d'apprentissage. Célèbre-les !"

### Sur le code :

> "Code is read more than it is written" - Écris pour les humains d'abord.

> "Premature optimization is the root of all evil" - Fais marcher, puis optimise.

> "Simple is better than complex" - Principe du Zen of Python.

### Sur la pratique :

> "You don't learn to walk by following rules. You learn by doing, and falling over."

> "The only way to learn a new programming language is by writing programs in it."

> "Build projects, not just complete exercises."

---

## [HOT] MOTIVATION ET MINDSET

### Quand c'est difficile :

- [LOGIQUE] **C'est normal** - La difficulté signifie que tu apprends
- [OBJECTIF] **Persistance > talent** - La régularité bat le génie
- [HAUSSE] **Progression non-linéaire** - Parfois tu stagnes, puis boom, déclic !
- [ACCORD] **Demande de l'aide** - La communauté Python est bienveillante
- [BRAVO] **Célèbre les petites victoires** - Chaque exercice complété compte

### Règles d'or :

1. **Code tous les jours** - Même 15 minutes
2. **Fais des pauses** - Ton cerveau consolide pendant le repos
3. **Varie les exercices** - Alterne facile/difficile pour garder la motivation
4. **Enseigne** - Explique à quelqu'un = révise et solidifie
5. **Build in public** - Partage ta progression, inspire les autres

---

## [BRAVO] CONCLUSION

Tu as maintenant entre les mains un **parcours complet et structuré** pour maîtriser Python de A à Z.

**520 exercices** qui couvrent :

- [OK] Les fondamentaux (variables, boucles, fonctions)
- [OK] La POO complète (classes, héritage, abstractions)
- [OK] Le développement web (Flask, Django, FastAPI)
- [OK] La data science et le ML (Pandas, Scikit-learn, TensorFlow)
- [OK] Les concepts avancés (async, métaprogrammation, patterns)
- [OK] Les outils professionnels (Git, tests, CI/CD, Docker)
- [OK] Les spécialisations (DevOps, Cybersécurité, IA)

### [RAPIDE] Commence MAINTENANT !

Ne te laisse pas intimider par les 520 exercices. Commence simplement par :

**-> Exercice 1.1 : Affiche "Bienvenue dans le monde de Python !"**

Puis passe au suivant. Et encore au suivant.

Un jour tu regarderas en arrière et tu seras étonné du chemin parcouru. *

### [FORCE] Tu peux le faire !

Des milliers de développeurs sont passés de "je ne sais rien" à "expert Python" en suivant exactement ce type de progression structurée.

**Tu seras le prochain.** [OBJECTIF]

---

**Bon courage dans ton parcours vers l'expertise Python ! [PYTHON]***

_"Le voyage de mille lieues commence par un premier pas."_ - Lao Tseu

---

## [TEL] DERNIERS CONSEILS

1. **Sauvegarde ce document** - Tu vas y revenir souvent
2. **Crée ton environnement** - Setup VS Code, Python, Git dès maintenant
3. **Rejoins des communautés** - Discord, Reddit, forums Python
4. **Fixe-toi des objectifs** - "Cette semaine je finis les chapitres 1-3"
5. **Track ta progression** - Utilise le template fourni
6. **Partage ton code** - GitHub dès le début, même si imparfait
7. **Ne compare pas** - Ton seul concurrent c'est toi d'hier
8. **Profite du voyage** - Le but n'est pas juste la destination, mais la transformation

**[OBJECTIF] ACTION IMMÉDIATE :**  
Ouvre ton éditeur de code MAINTENANT et écris :

```python
print("Je commence mon voyage Python aujourd'hui !")
```

C'est parti ! [RAPIDE][PYTHON]# [PYTHON] 520 Exercices Python Complets - De Débutant à Expert

**Guide d'utilisation :**

- Chaque chapitre contient 10 exercices progressifs
- Les exercices explorent toutes les fonctionnalités du sujet traité
- Faites les exercices dans l'ordre pour une progression optimale
- N'hésitez pas à tester et modifier votre code

---
