Software Engineering">
[Go to site: main page, start]

0% ont trouvé ce document utile (0 vote)
2 vues79 pages

Cours Python

Ce document est un cours complet sur Python, couvrant les bases du langage, les structures de contrôle, les fonctions et les structures de données. Il inclut des exemples de code et des exercices pratiques pour renforcer l'apprentissage. Les concepts abordés incluent les variables, les types de données, les opérateurs, les boucles, les conditions, les fonctions, les listes, les tuples, les dictionnaires et les ensembles.

Transféré par

pwd.mathis
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
2 vues79 pages

Cours Python

Ce document est un cours complet sur Python, couvrant les bases du langage, les structures de contrôle, les fonctions et les structures de données. Il inclut des exemples de code et des exercices pratiques pour renforcer l'apprentissage. Les concepts abordés incluent les variables, les types de données, les opérateurs, les boucles, les conditions, les fonctions, les listes, les tuples, les dictionnaires et les ensembles.

Transféré par

pwd.mathis
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Cours Complet Python — Bases à la POO

Chapitre 1 — Les bases du langage

1.1 Variables et types de données

Une variable est une boîte qui stocke une valeur. En Python, pas besoin de déclarer le type, il
est détecté automatiquement.

python

nom = "Mathis" # str → texte

age = 20 # int → entier

taille = 1.80 # float → décimal

majeur = True # bool → True / False

rien = None # NoneType → absence de valeur

Tu peux vérifier le type avec type() :

python

print(type(nom)) # <class 'str'>

print(type(age)) # <class 'int'>

Et convertir d'un type à l'autre :

python

age_texte = str(age) # "20"

nombre = int("42") # 42

decimal = float("3.14") # 3.14

1.2 Opérateurs

Arithmétiques :

python

print(10 + 3) # 13 → addition

print(10 - 3) # 7 → soustraction

print(10 * 3) # 30 → multiplication
print(10 / 3) # 3.333... → division réelle

print(10 // 3) # 3 → division entière (arrondi bas)

print(10 % 3) # 1 → modulo (reste de la division)

print(2 ** 8) # 256 → puissance

Comparaison (retournent True ou False) :

python

print(5 == 5) # True → égalité

print(5 != 3) # True → différence

print(5 > 3) # True → supérieur

print(5 <= 5) # True → inférieur ou égal

Logiques :

python

print(True and False) # False → les deux doivent être True

print(True or False) # True → au moins un True suffit

print(not True) # False → inverse

1.3 Affichage et saisie

python

# Affichage simple

print("Bonjour !")

print("Valeur :", 42)

# F-strings (la façon moderne et recommandée)

nom = "Mathis"

age = 20

print(f"Je m'appelle {nom} et j'ai {age} ans.")

# → Je m'appelle Mathis et j'ai 20 ans.


# Tu peux faire des calculs dans les f-strings

print(f"Dans 10 ans j'aurai {age + 10} ans.")

# Saisie utilisateur (retourne toujours une str !)

prenom = input("Ton prénom : ")

annee = int(input("Ton année de naissance : ")) # convertir en int

Exercice 1 — Présentation

Écris un programme qui :

1. Demande à l'utilisateur son prénom, son âge et sa ville.

2. Calcule son année de naissance approximative (2026 - âge).

3. Affiche une phrase du type : "Bonjour Mathis ! Tu habites à Lyon, tu es né(e) vers
2006 et dans 10 ans tu auras 30 ans."

Solution :

python

prenom = input("Ton prénom : ")

age = int(input("Ton âge : "))

ville = input("Ta ville : ")

annee_naissance = 2026 - age

age_dans_10_ans = age + 10

print(f"Bonjour {prenom} ! Tu habites à {ville}, "

f"tu es né(e) vers {annee_naissance} "

f"et dans 10 ans tu auras {age_dans_10_ans} ans.")

Chapitre 2 — Structures de contrôle


2.1 Conditions — if / elif / else

python

note = 14

if note >= 16:

print("Très bien")

elif note >= 14:

print("Bien")

elif note >= 10:

print("Passable")

else:

print("Insuffisant")

Python utilise l'indentation (4 espaces) pour délimiter les blocs. Pas d'accolades comme
en C ou Java.

Tu peux aussi écrire une condition en une ligne (ternaire) :

python

statut = "majeur" if age >= 18 else "mineur"

print(statut)

2.2 Boucle for

La boucle for parcourt une séquence (liste, chaîne, range...) :

python

# range(n) → génère 0, 1, 2, ..., n-1

for i in range(5):

print(i) # 0, 1, 2, 3, 4

# range(début, fin, pas)

for i in range(0, 20, 5):


print(i) # 0, 5, 10, 15

# Parcourir une chaîne

for lettre in "Python":

print(lettre) # P, y, t, h, o, n

# Parcourir une liste

fruits = ["pomme", "banane", "cerise"]

for fruit in fruits:

print(fruit)

2.3 Boucle while

La boucle while tourne tant qu'une condition est vraie :

python

compteur = 0

while compteur < 5:

print(compteur)

compteur += 1 # IMPORTANT : ne pas oublier sinon boucle infinie !

Contrôle de boucle :

python

# break → quitter la boucle immédiatement

for i in range(10):

if i == 5:

break

print(i) # affiche 0, 1, 2, 3, 4

# continue → passer à l'itération suivante

for i in range(6):
if i == 3:

continue

print(i) # affiche 0, 1, 2, 4, 5

# pass → ne rien faire (placeholder)

for i in range(5):

pass # boucle vide, ne plante pas

Exercice 2 — FizzBuzz (classique incontournable)

Affiche les nombres de 1 à 50. Mais :

• Si divisible par 3 → affiche Fizz

• Si divisible par 5 → affiche Buzz

• Si divisible par 3 ET 5 → affiche FizzBuzz

• Sinon → affiche le nombre

Astuce : teste d'abord % 15 (multiple de 3 ET 5) avant les autres cas.

Solution :

python

for i in range(1, 51):

if i % 15 == 0:

print("FizzBuzz")

elif i % 3 == 0:

print("Fizz")

elif i % 5 == 0:

print("Buzz")

else:

print(i)

Exercice 3 — Devine le nombre


Génère un nombre aléatoire entre 1 et 100. Demande à l'utilisateur de le deviner. À chaque
essai, indique si c'est trop grand, trop petit ou trouvé ! Compte le nombre d'essais.

Solution :

python

import random

secret = [Link](1, 100)

essais = 0

trouve = False

while not trouve:

guess = int(input("Ton nombre : "))

essais += 1

if guess < secret:

print("Trop petit !")

elif guess > secret:

print("Trop grand !")

else:

print(f"Bravo ! Trouvé en {essais} essais.")

trouve = True

Chapitre 3 — Fonctions

3.1 Définir et appeler une fonction

Une fonction est un bloc de code réutilisable qu'on nomme.

python

def saluer(prenom):
"""Cette ligne s'appelle une docstring, elle documente la fonction."""

message = f"Bonjour, {prenom} !"

return message

resultat = saluer("Mathis")

print(resultat) # Bonjour, Mathis !

return renvoie une valeur. Sans return, la fonction renvoie None.

Une fonction peut retourner plusieurs valeurs (sous forme de tuple) :

python

def stats(liste):

return min(liste), max(liste), sum(liste) / len(liste)

mini, maxi, moy = stats([10, 5, 8, 20, 3])

print(mini, maxi, moy) # 3 20 9.2

3.2 Arguments par défaut

python

def puissance(base, exposant=2): # exposant vaut 2 par défaut

return base ** exposant

print(puissance(5)) # 25 (exposant = 2 par défaut)

print(puissance(5, 3)) # 125

print(puissance(exposant=4, base=2)) # 16 → arguments nommés

3.3 *args et **kwargs

python

# *args → reçoit autant d'arguments positionnels qu'on veut

def total(*nombres):
return sum(nombres)

print(total(1, 2, 3)) #6

print(total(10, 20, 30, 40)) # 100

# **kwargs → reçoit autant d'arguments nommés qu'on veut

def afficher_profil(**infos):

for cle, valeur in [Link]():

print(f" {cle} : {valeur}")

afficher_profil(nom="Mathis", age=20, ville="Lyon")

# nom : Mathis

# age : 20

# ville : Lyon

3.4 Fonctions lambda

Une lambda est une fonction anonyme en une seule ligne :

python

double = lambda x: x * 2

print(double(7)) # 14

additionner = lambda a, b: a + b

print(additionner(3, 4)) # 7

# Très utiles avec sorted(), map(), filter()

noms = ["Charlie", "Alice", "Bob", "Diana"]

[Link](key=lambda n: len(n)) # trier par longueur

print(noms) # ['Bob', 'Alice', 'Diana', 'Charlie']


Exercice 4 — Calculatrice

Écris une fonction calculer(a, operateur, b) qui supporte +, -, *, /, ** et %.

• Retourne le résultat.

• Affiche une erreur propre si division par zéro.

• Retourne None si l'opérateur est inconnu.

Solution :

python

def calculer(a, operateur, b):

if operateur == "+":

return a + b

elif operateur == "-":

return a - b

elif operateur == "*":

return a * b

elif operateur == "/":

if b == 0:

print("Erreur : division par zéro impossible.")

return None

return a / b

elif operateur == "**":

return a ** b

elif operateur == "%":

return a % b

else:

print(f"Opérateur '{operateur}' inconnu.")

return None
print(calculer(10, "/", 0)) # Erreur : division par zéro impossible.

print(calculer(7, "*", 6)) # 42

print(calculer(2, "**", 10)) # 1024

Exercice 5 — Suite de Fibonacci

Écris une fonction fibonacci(n) qui retourne la liste des n premiers termes de la suite de
Fibonacci. La suite commence par [0, 1] et chaque terme suivant est la somme des deux
précédents : 0, 1, 1, 2, 3, 5, 8, 13, ...

Solution :

python

def fibonacci(n):

if n <= 0:

return []

if n == 1:

return [0]

suite = [0, 1]

while len(suite) < n:

[Link](suite[-1] + suite[-2])

return suite

print(fibonacci(10))

# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Chapitre 4 — Structures de données

4.1 Listes

La liste est la structure la plus utilisée. Elle est ordonnée et mutable (modifiable).

python
fruits = ["pomme", "banane", "cerise", "mangue"]

# Accès par index (commence à 0)

print(fruits[0]) # pomme

print(fruits[-1]) # mangue (dernier élément)

print(fruits[-2]) # cerise (avant-dernier)

# Slicing [début:fin:pas] — fin exclue

print(fruits[1:3]) # ['banane', 'cerise']

print(fruits[:2]) # ['pomme', 'banane']

print(fruits[2:]) # ['cerise', 'mangue']

print(fruits[::2]) # ['pomme', 'cerise'] (un sur deux)

print(fruits[::-1]) # liste inversée

Méthodes essentielles :

python

[Link]("kiwi") # ajoute à la fin

[Link](1, "fraise") # insère à l'index 1

[Link]("banane") # supprime par valeur (1ère occurrence)

[Link]() # supprime et retourne le dernier

[Link](0) # supprime et retourne l'index 0

[Link]() # trie en place

[Link](reverse=True) # trie en ordre décroissant

[Link]() # inverse en place

[Link]("pomme") # nombre d'occurrences

[Link]("cerise") # position de "cerise"

len(fruits) # longueur

"pomme" in fruits # True si présent


4.2 Tuples

Immuables (non modifiables). Parfaits pour des données fixes ou pour retourner plusieurs
valeurs.

python

point = (3, 7)

couleur = (255, 128, 0) # RGB orange

coordonnees = (48.8566, 2.3522)

# Unpacking

x, y = point

print(x, y) # 3 7

r, g, b = couleur

lat, lon = coordonnees

# Un tuple d'un seul élément (noter la virgule !)

singleton = (42,)

4.3 Dictionnaires

Paires clé : valeur, ordonnés (Python 3.7+), mutables.

python

joueur = {

"nom": "Mathis",

"niveau": 12,

"vies": 3,

"score": 8450

}
# Accès

print(joueur["nom"]) # Mathis

print([Link]("mana", 100)) # 100 (valeur par défaut si absent)

# Modification / ajout

joueur["niveau"] = 13

joueur["xp"] = 2500

# Suppression

del joueur["vies"]

[Link]("xp") # supprime et retourne la valeur

# Parcourir

for cle in joueur:

print(cle)

for cle, val in [Link]():

print(f"{cle} → {val}")

# Vérifier l'existence

if "score" in joueur:

print("Score trouvé !")

4.4 Sets (ensembles)

Non ordonnés, sans doublons. Très rapides pour tester l'appartenance.

python

couleurs = {"rouge", "bleu", "vert"}

[Link]("jaune")
[Link]("rouge") # ne plante pas si absent

# Opérations ensemblistes

a = {1, 2, 3, 4, 5}

b = {3, 4, 5, 6, 7}

print(a & b) # {3, 4, 5} → intersection

print(a | b) # {1,2,3,4,5,6,7} → union

print(a - b) # {1, 2} → différence

print(a ^ b) # {1, 2, 6, 7} → différence symétrique

# Supprimer les doublons d'une liste

avec_doublons = [1, 2, 2, 3, 3, 3, 4]

sans_doublons = list(set(avec_doublons))

Exercice 6 — Gestion d'inventaire

Crée un dictionnaire inventaire = {"épée": 1, "potion": 5, "flèche": 30}.

Écris trois fonctions :

• ajouter(inv, objet, qte) — ajoute la quantité (crée l'objet s'il n'existe pas)

• retirer(inv, objet, qte) — retire la quantité, affiche une erreur si stock insuffisant,
supprime l'entrée si quantité = 0

• afficher(inv) — affiche chaque objet aligné avec sa quantité

Solution :

python

inventaire = {"épée": 1, "potion": 5, "flèche": 30}

def ajouter(inv, objet, qte):

inv[objet] = [Link](objet, 0) + qte


print(f"+{qte} {objet} ajouté(s). Total : {inv[objet]}")

def retirer(inv, objet, qte):

if [Link](objet, 0) < qte:

print(f"Erreur : stock insuffisant pour '{objet}'.")

return

inv[objet] -= qte

if inv[objet] == 0:

del inv[objet]

print(f"'{objet}' épuisé, retiré de l'inventaire.")

else:

print(f"-{qte} {objet}. Restant : {inv[objet]}")

def afficher(inv):

print("─── Inventaire ───")

for objet, qte in sorted([Link]()):

print(f" {objet:<15} x{qte}")

ajouter(inventaire, "bouclier", 1)

retirer(inventaire, "potion", 5) # épuise les potions

afficher(inventaire)

Chapitre 5 — Chaînes de caractères

5.1 Méthodes essentielles

python

texte = " Bonjour, Python ! "


# Nettoyage

[Link]() # "Bonjour, Python !" — supprime les espaces en bord

[Link]() # supprime à gauche seulement

[Link]() # supprime à droite seulement

# Casse

[Link]() # "bonjour, python !"

[Link]() # "BONJOUR, PYTHON !"

[Link]() # "Bonjour, Python !" — 1ère lettre en maj

[Link]() # " bonjour, python !" — seulement la 1ère

# Recherche & remplacement

[Link]("Python", "Monde") # " Bonjour, Monde ! "

[Link]("Python") # index de début, -1 si absent

[Link]("o") # nombre d'occurrences

"Python" in texte # True

# Découpage / assemblage

"un,deux,trois".split(",") # ['un', 'deux', 'trois']

"hello".split() # ['hello'] (espace par défaut)

" - ".join(["un", "deux", "trois"]) # "un - deux - trois"

# Vérifications (retournent True/False)

"123".isdigit() # True

"abc".isalpha() # True

"abc123".isalnum() # True

" ".isspace() # True

"Hello".startswith("He") # True
"Hello".endswith("lo") # True

5.2 F-strings avancées

python

nom = "Mathis"

score = 1234.5678

pi = 3.14159

# Décimales

print(f"{score:.2f}") # 1234.57

print(f"{pi:.4f}") # 3.1416

# Alignement et largeur

print(f"{nom:>15}") #" Mathis" (aligné à droite, 15 chars)

print(f"{nom:<15}") # "Mathis " (aligné à gauche)

print(f"{nom:^15}") # " Mathis " (centré)

print(f"{nom:*^15}") # "****Mathis*****" (centré avec remplissage *)

# Entiers

print(f"{1000000:,}") # 1,000,000 (séparateur milliers)

print(f"{255:08b}") # 11111111 (binaire sur 8 bits)

print(f"{255:02x}") # ff (hexadécimal)

# Calculs inline

print(f"2 ** 10 = {2**10}") # 2 ** 10 = 1024

Exercice 7 — Analyseur de texte

Écris une fonction analyser(texte) qui affiche :


• Le nombre de mots

• Le nombre de phrases (se termine par ., ! ou ?)

• Le mot le plus fréquent

• Le mot le plus long

• Le texte avec chaque mot commençant par une majuscule

Solution :

python

def analyser(texte):

mots = [Link]().split()

phrases = [Link](".") + [Link]("!") + [Link]("?")

# Fréquence des mots (sans ponctuation)

freq = {}

for mot in mots:

mot_propre = [Link](".,!?;:")

freq[mot_propre] = [Link](mot_propre, 0) + 1

mot_frequent = max(freq, key=[Link])

mot_long = max(mots, key=len).strip(".,!?;:")

print(f"Mots : {len(mots)}")

print(f"Phrases : {phrases}")

print(f"Mot fréquent : '{mot_frequent}' ({freq[mot_frequent]}x)")

print(f"Mot le + long : '{mot_long}'")

print(f"En titre : {[Link]()}")

analyser("Python est génial. Python est simple et puissant ! Tu aimes Python ?")
Chapitre 6 — Modules et fichiers

6.1 Modules standard incontournables

python

import math

[Link](16) # 4.0 — racine carrée

[Link](3.2) # 4 — arrondi supérieur

[Link](3.9) # 3 — arrondi inférieur

[Link] # 3.14159...

[Link](100, 10) # 2.0 — logarithme base 10

import random

[Link](1, 6) # entier entre 1 et 6 inclus

[Link]() # float entre 0.0 et 1.0

[Link](["A", "B", "C"]) # élément aléatoire

[Link](liste) # mélange en place

[Link](liste, 3) # 3 éléments sans répétition

from datetime import datetime, timedelta

now = [Link]()

print([Link]("%d/%m/%Y %H:%M")) # 24/03/2026 09:30

hier = now - timedelta(days=1)

import os

[Link]() # dossier courant

[Link](".") # contenu du dossier

[Link]("fich") # True si le fichier existe

[Link]("dossier") # crée un dossier (et ses parents)


6.2 Lecture et écriture de fichiers

python

# Écriture (crée ou écrase le fichier)

with open("[Link]", "w", encoding="utf-8") as f:

[Link]("Ligne 1\n")

[Link]("Ligne 2\n")

# Ajout à la fin (mode "a")

with open("[Link]", "a", encoding="utf-8") as f:

[Link]("Ligne 3\n")

# Lecture complète

with open("[Link]", "r", encoding="utf-8") as f:

contenu = [Link]()

print(contenu)

# Lecture ligne par ligne (économe en mémoire)

with open("[Link]", "r", encoding="utf-8") as f:

for ligne in f:

print([Link]())

# Lecture de toutes les lignes dans une liste

with open("[Link]", "r", encoding="utf-8") as f:

lignes = [Link]() # ['"Ligne 1\n", "Ligne 2\n", ...]

Toujours utiliser with open(...) — il ferme automatiquement le fichier même en cas


d'erreur.
Chapitre 7 — Gestion des erreurs

7.1 try / except / finally

python

try:

x = int(input("Entrez un nombre : "))

resultat = 100 / x

print(f"100 / {x} = {resultat}")

except ValueError:

print("Erreur : veuillez entrer un nombre entier.")

except ZeroDivisionError:

print("Erreur : impossible de diviser par zéro.")

except Exception as e:

print(f"Erreur inattendue : {e}")

else:

print("Tout s'est bien passé !") # exécuté si PAS d'erreur

finally:

print("Ce bloc s'exécute TOUJOURS.")

Erreurs courantes à connaître :

Exception Cause typique

ValueError int("abc") — mauvais type de valeur

TypeError "2" + 2 — types incompatibles


Exception Cause typique

IndexError liste[99] — index hors limites

KeyError dico["clé"] — clé absente

ZeroDivisionError x / 0

FileNotFoundError fichier inexistant

AttributeError attribut inexistant sur un objet

7.2 Lever ses propres exceptions

python

def verifier_age(age):

if not isinstance(age, int):

raise TypeError("L'âge doit être un entier.")

if age < 0 or age > 150:

raise ValueError(f"Âge invalide : {age}. Doit être entre 0 et 150.")

return age

try:

verifier_age(-5)

except ValueError as e:

print(e) # Âge invalide : -5. Doit être entre 0 et 150.

Exercice 8 — Saisie robuste

Écris une fonction demander_entier(message, mini, maxi) qui :

• Demande en boucle jusqu'à obtenir un entier valide

• Vérifie que la valeur est entre mini et maxi

• Affiche un message d'erreur clair à chaque tentative invalide

• Retourne la valeur valide


Solution :

python

def demander_entier(message, mini, maxi):

while True:

try:

valeur = int(input(message))

if valeur < mini or valeur > maxi:

print(f"Erreur : entrez un nombre entre {mini} et {maxi}.")

else:

return valeur

except ValueError:

print("Erreur : ce n'est pas un nombre entier.")

age = demander_entier("Votre âge : ", 0, 150)

print(f"Âge enregistré : {age}")

Chapitre 8 — Programmation Orientée Objet

8.1 Classe et objet

Une classe est un modèle (plan). Un objet est une instance de ce modèle.

python

class Personnage:

"""Un personnage de jeu vidéo."""

def __init__(self, nom, vie=100, force=10):

# self = l'objet lui-même

[Link] = nom

[Link] = vie
[Link] = force

[Link] = 1

[Link] = True

def attaquer(self, cible):

if not [Link]:

print(f"{[Link]} est mort et ne peut pas attaquer.")

return

degats = [Link]

cible.recevoir_degats(degats)

print(f"{[Link]} attaque {[Link]} pour {degats} dégâts !")

def recevoir_degats(self, degats):

[Link] -= degats

if [Link] <= 0:

[Link] = 0

[Link] = False

print(f"{[Link]} est mort !")

def soigner(self, soin):

[Link] = min([Link] + soin, 100) # max 100

print(f"{[Link]} récupère {soin} PV. Vie : {[Link]}")

def __str__(self):

statut = "vivant" if [Link] else "mort"

return f"{[Link]} | Niv.{[Link]} | {[Link]} | {statut}"


# Créer des objets

hero = Personnage("Arthas", vie=150, force=20)

gobelin = Personnage("Goblin", vie=40, force=8)

[Link](gobelin) # Arthas attaque Goblin pour 20 dégâts !

print(gobelin) # Goblin | Niv.1 | 20 | vivant

[Link](gobelin) # Goblin est mort !

8.2 Attributs de classe vs d'instance

python

class Compteur:

instances = 0 # attribut de CLASSE (partagé par tous)

def __init__(self, nom):

[Link] = nom # attribut d'INSTANCE

[Link] += 1

@classmethod

def combien(cls):

return [Link]

@staticmethod

def aide():

return "Je compte les instances créées."

c1 = Compteur("A")

c2 = Compteur("B")
print([Link]()) # 2

print([Link]())

8.3 Héritage

python

class Magicien(Personnage): # hérite de Personnage

def __init__(self, nom):

super().__init__(nom, vie=80, force=5) # appel du parent

[Link] = 100

[Link] = []

def apprendre_sort(self, sort):

[Link](sort)

print(f"{[Link]} apprend '{sort}' !")

def lancer_sort(self, cible, sort, degats):

if sort not in [Link]:

print(f"{[Link]} ne connaît pas '{sort}'.")

return

if [Link] < 20:

print("Mana insuffisant !")

return

cible.recevoir_degats(degats * 2) # sorts = double dégâts

[Link] -= 20

print(f"{[Link]} lance '{sort}' → {degats*2} dégâts magiques !")

def __str__(self):
base = super().__str__()

return f"{base} | {[Link]} mana"

mage = Magicien("Gandalf")

mage.apprendre_sort("Boule de feu")

mage.lancer_sort(gobelin, "Boule de feu", 15)

print(mage)

8.4 Méthodes spéciales (dunder methods)

python

class Vecteur:

def __init__(self, x, y):

self.x = x

self.y = y

def __str__(self): # print(v) → affichage lisible

return f"Vecteur({self.x}, {self.y})"

def __repr__(self): # représentation technique

return f"Vecteur(x={self.x}, y={self.y})"

def __add__(self, autre): # v1 + v2

return Vecteur(self.x + autre.x, self.y + autre.y)

def __len__(self): # len(v)

return int((self.x**2 + self.y**2) ** 0.5)


def __eq__(self, autre): # v1 == v2

return self.x == autre.x and self.y == autre.y

v1 = Vecteur(3, 4)

v2 = Vecteur(1, 2)

print(v1 + v2) # Vecteur(4, 6)

print(len(v1)) # 5 (norme entière)

print(v1 == v2) # False

Exercice 9 — Banque orientée objet

Crée une classe CompteBancaire :

• Attributs : titulaire, solde (défaut 0), historique (liste des transactions)

• Méthodes : deposer(montant), retirer(montant), afficher_historique()

• Gère les erreurs (montant négatif, solde insuffisant)

Puis crée CompteEpargne(CompteBancaire) avec une méthode appliquer_interets(taux_pct).

Solution :

python

class CompteBancaire:

def __init__(self, titulaire, solde=0):

[Link] = titulaire

[Link] = solde

[Link] = []

def deposer(self, montant):

if montant <= 0:

raise ValueError("Le montant doit être positif.")

[Link] += montant
[Link](f"+{montant}€ (dépôt)")

print(f"Dépôt de {montant}€. Solde : {[Link]}€")

def retirer(self, montant):

if montant <= 0:

raise ValueError("Le montant doit être positif.")

if montant > [Link]:

raise ValueError("Solde insuffisant.")

[Link] -= montant

[Link](f"-{montant}€ (retrait)")

print(f"Retrait de {montant}€. Solde : {[Link]}€")

def afficher_historique(self):

print(f"\n── Historique de {[Link]} ──")

for ligne in [Link]:

print(f" {ligne}")

print(f" Solde actuel : {[Link]}€\n")

def __str__(self):

return f"Compte de {[Link]} : {[Link]}€"

class CompteEpargne(CompteBancaire):

def appliquer_interets(self, taux_pct):

interets = [Link] * taux_pct / 100

[Link] += interets

[Link](f"+{interets:.2f}€ (intérêts {taux_pct}%)")

print(f"Intérêts de {taux_pct}% : +{interets:.2f}€. Solde : {[Link]:.2f}€")


# Test

compte = CompteEpargne("Mathis", 1000)

[Link](500)

[Link](200)

compte.appliquer_interets(3)

compte.afficher_historique()

Chapitre 9 — Notions intermédiaires

9.1 Compréhensions

python

# List comprehension

carres = [x**2 for x in range(10)]

# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

pairs = [x for x in range(20) if x % 2 == 0]

# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# Imbriqué — produit cartésien

paires = [(x, y) for x in range(3) for y in range(3)]

# [(0,0), (0,1), (0,2), (1,0), ...]

# Dict comprehension

mots = ["chat", "chien", "oiseau"]

longueurs = {mot: len(mot) for mot in mots}

# {'chat': 4, 'chien': 5, 'oiseau': 6}


# Set comprehension

lettres = {lettre for lettre in "bonjour"}

# {'b', 'o', 'n', 'j', 'u', 'r'} — sans doublons

9.2 enumerate, zip, sorted

python

# enumerate → donne index + valeur

fruits = ["pomme", "banane", "cerise"]

for i, fruit in enumerate(fruits, start=1):

print(f"{i}. {fruit}")

# 1. pomme 2. banane 3. cerise

# zip → parcourir plusieurs listes ensemble

noms = ["Alice", "Bob", "Charlie"]

scores = [95, 80, 72]

for nom, score in zip(noms, scores):

print(f"{nom} : {score}/100")

# sorted → retourne une NOUVELLE liste triée

nombres = [3, 1, 4, 1, 5, 9, 2, 6]

tries = sorted(nombres) # croissant

desc = sorted(nombres, reverse=True) # décroissant

joueurs = [{"nom": "Alice", "pts": 95}, {"nom": "Bob", "pts": 80}]

classe = sorted(joueurs, key=lambda j: j["pts"], reverse=True)

9.3 map et filter


python

nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# map → applique une fonction à chaque élément

doubles = list(map(lambda x: x * 2, nombres))

# [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# filter → garde les éléments qui satisfont une condition

pairs = list(filter(lambda x: x % 2 == 0, nombres))

# [2, 4, 6, 8, 10]

# reduce → accumule (nécessite functools)

from functools import reduce

produit = reduce(lambda acc, x: acc * x, [1, 2, 3, 4, 5])

# 120 (= 1 × 2 × 3 × 4 × 5)

Exercice 10 — Projet final : Gestionnaire de notes

Crée un programme complet qui :

1. Stocke des étudiants et leurs notes.

2. Calcule la moyenne de chaque étudiant.

3. Attribue une mention selon la moyenne.

4. Trie par moyenne décroissante.

5. Affiche le classement formaté.

6. Sauvegarde dans [Link].

Solution :

python

etudiants = {

"Alice": [15, 17, 14, 16, 18],


"Bob": [10, 12, 9, 11, 8],

"Charlie": [18, 19, 17, 20, 16],

"Diana": [ 8, 7, 9, 6, 10],

"Evan": [13, 12, 14, 11, 15],

def mention(moy):

if moy >= 16: return "Très bien "

if moy >= 14: return "Bien "

if moy >= 10: return "Passable "

return "Insuffisant "

# Calcul des moyennes

resultats = [

"nom": nom,

"moy": sum(notes) / len(notes),

"mention": mention(sum(notes) / len(notes))

for nom, notes in [Link]()

# Tri par moyenne décroissante

[Link](key=lambda e: e["moy"], reverse=True)

# Affichage + sauvegarde

lignes = ["=== Classement des étudiants ===\n"]

for rang, e in enumerate(resultats, 1):


ligne = f"{rang}. {e['nom']:<10} {e['moy']:5.2f}/20 {e['mention']}"

print(ligne)

[Link](ligne + "\n")

with open("[Link]", "w", encoding="utf-8") as f:

[Link](lignes)

print("\nClassement sauvegardé dans [Link] ")

Récapitulatif — Ce que tu maîtrises maintenant

Notion Chapitres

Variables, types, opérateurs 1

Conditions et boucles 2

Fonctions, lambda, *args 3

Listes, tuples, dicts, sets 4

Chaînes et f-strings 5

Modules standard et fichiers 6

Gestion des erreurs 7

Classes, héritage, dunder 8

Compréhensions, zip, map 9

Prochaines étapes recommandées :

• Décorateurs (@property, @staticmethod, créer les siens)

• Générateurs (yield)

• Modules json, csv, re (regex)

• Bibliothèques : requests, pandas, pygame selon tes projets

Peut tu ajouter un cours sur le module os, json, tkinter, threading

07:31
Chapitre 10 — Le module os

Le module os permet d'interagir avec le système de fichiers et le système d'exploitation.

10.1 Navigation et informations

python

import os

# Dossier courant

print([Link]()) # /home/mathis/projets

# Changer de dossier

[Link]("/home/mathis/Documents")

# Lister le contenu d'un dossier

contenu = [Link](".") # liste tous les fichiers/dossiers

for item in contenu:

print(item)

# Informations sur un chemin

[Link]("[Link]") # True si existe

[Link]("[Link]") # True si c'est un fichier

[Link]("dossier") # True si c'est un dossier

[Link]("[Link]") # taille en octets

[Link]("/a/b/[Link]") # "[Link]"

[Link]("/a/b/[Link]") # "/a/b"

[Link]("[Link]") # ("fichier", ".txt")

# Construire un chemin (compatible Windows/Linux/Mac)

chemin = [Link]("dossier", "sous-dossier", "[Link]")


print(chemin) # dossier/sous-dossier/[Link] (ou \ sur Windows)

10.2 Créer, renommer, supprimer

python

import os

# Créer des dossiers

[Link]("nouveau_dossier") # crée un dossier (erreur si existe déjà)

[Link]("a/b/c", exist_ok=True) # crée tous les dossiers intermédiaires

# Renommer / déplacer

[Link]("ancien_nom.txt", "nouveau_nom.txt")

# Supprimer

[Link]("[Link]") # supprime un fichier

[Link]("dossier_vide") # supprime un dossier VIDE seulement

# Pour supprimer un dossier non vide :

import shutil

[Link]("dossier_avec_contenu") # irrécupérable !

[Link]("[Link]", "[Link]") # copier un fichier

[Link]("[Link]", "destination/") # déplacer

10.3 Parcourir une arborescence avec [Link]

[Link] est extrêmement utile pour explorer récursivement tous les fichiers d'un dossier.

python

import os
for dossier, sous_dossiers, fichiers in [Link]("."):

print(f"\n {dossier}")

for fichier in fichiers:

chemin_complet = [Link](dossier, fichier)

taille = [Link](chemin_complet)

print(f" {fichier} ({taille} octets)")

10.4 Variables d'environnement

python

import os

# Lire une variable d'environnement

path = [Link]("PATH", "non défini")

maison = [Link]("HOME")

# Définir une variable (pour ce processus uniquement)

[Link]["MON_APP_MODE"] = "debug"

# Exemple concret : clé API stockée en variable d'environnement

api_key = [Link]("API_KEY")

if not api_key:

raise EnvironmentError("La variable API_KEY n'est pas définie !")

Exercice 11 — Explorateur de fichiers

Écris une fonction scanner_dossier(chemin) qui :

1. Parcourt récursivement le dossier donné.

2. Compte le nombre de fichiers par extension (.py, .txt, .jpg...).

3. Calcule la taille totale de chaque type.


4. Affiche un rapport trié par nombre de fichiers décroissant.

Solution :

python

import os

def scanner_dossier(chemin):

stats = {} # {"ext": {"nb": 0, "taille": 0}}

for dossier, _, fichiers in [Link](chemin):

for fichier in fichiers:

_, ext = [Link](fichier)

ext = [Link]() if ext else "(sans extension)"

chemin_f = [Link](dossier, fichier)

if ext not in stats:

stats[ext] = {"nb": 0, "taille": 0}

stats[ext]["nb"] += 1

stats[ext]["taille"] += [Link](chemin_f)

print(f"\n{'Extension':<20} {'Fichiers':>10} {'Taille':>15}")

print("─" * 47)

for ext, info in sorted([Link](), key=lambda x: x[1]["nb"], reverse=True):

taille_ko = info["taille"] / 1024

print(f"{ext:<20} {info['nb']:>10} {taille_ko:>13.1f} Ko")

scanner_dossier(".")
Chapitre 11 — Le module json

JSON (JavaScript Object Notation) est le format d'échange de données le plus utilisé sur le
web. Python le gère nativement.

11.1 Les équivalences Python ↔ JSON

Python JSON

dict object {}

list array []

str string ""

int, float number

True / False true / false

None null

11.2 Sérialisation — Python → JSON

python

import json

joueur = {

"nom": "Mathis",

"niveau": 12,

"vies": 3,

"actif": True,

"scores": [1200, 850, 2100],

"position": {"x": 14.5, "y": 32.0}

# Convertir en chaîne JSON


texte_json = [Link](joueur)

print(texte_json)

# {"nom": "Mathis", "niveau": 12, ...}

# Avec indentation (lisible)

texte_joli = [Link](joueur, indent=4, ensure_ascii=False)

print(texte_joli)

# Sauvegarder dans un fichier

with open("[Link]", "w", encoding="utf-8") as f:

[Link](joueur, f, indent=4, ensure_ascii=False)

ensure_ascii=False est indispensable pour les caractères accentués (é, à, ç...).

11.3 Désérialisation — JSON → Python

python

import json

# Depuis une chaîne

texte = '{"nom": "Alice", "score": 95, "actif": true}'

data = [Link](texte)

print(data["nom"]) # Alice

print(type(data)) # <class 'dict'>

# Depuis un fichier

with open("[Link]", "r", encoding="utf-8") as f:

joueur = [Link](f)

print(joueur["nom"]) # Mathis
print(joueur["scores"][0]) # 1200

11.4 Cas pratique — Fichier de configuration

python

import json, os

FICHIER_CONFIG = "[Link]"

CONFIG_DEFAUT = {

"langue": "fr",

"theme": "sombre",

"volume": 80,

"plein_ecran": False

def charger_config():

if [Link](FICHIER_CONFIG):

with open(FICHIER_CONFIG, "r", encoding="utf-8") as f:

return [Link](f)

return CONFIG_DEFAUT.copy()

def sauvegarder_config(config):

with open(FICHIER_CONFIG, "w", encoding="utf-8") as f:

[Link](config, f, indent=4, ensure_ascii=False)

print("Configuration sauvegardée ")

# Utilisation

config = charger_config()
config["volume"] = 65

config["theme"] = "clair"

sauvegarder_config(config)

Exercice 12 — Carnet de contacts JSON

Crée un carnet de contacts persistant (sauvegardé en JSON) avec :

• ajouter_contact(nom, tel, email)

• rechercher_contact(nom) — recherche partielle insensible à la casse

• supprimer_contact(nom)

• lister_contacts()

Les données doivent survivre entre deux exécutions du programme.

Solution :

python

import json, os

FICHIER = "[Link]"

def charger():

if [Link](FICHIER):

with open(FICHIER, "r", encoding="utf-8") as f:

return [Link](f)

return []

def sauvegarder(contacts):

with open(FICHIER, "w", encoding="utf-8") as f:

[Link](contacts, f, indent=4, ensure_ascii=False)

def ajouter_contact(nom, tel, email):


contacts = charger()

[Link]({"nom": nom, "tel": tel, "email": email})

sauvegarder(contacts)

print(f"Contact '{nom}' ajouté ")

def rechercher_contact(terme):

contacts = charger()

resultats = [c for c in contacts if [Link]() in c["nom"].lower()]

if not resultats:

print("Aucun contact trouvé.")

for c in resultats:

print(f" {c['nom']} | {c['tel']} | {c['email']}")

def supprimer_contact(nom):

contacts = charger()

avant = len(contacts)

contacts = [c for c in contacts if c["nom"].lower() != [Link]()]

if len(contacts) == avant:

print(f"Contact '{nom}' introuvable.")

else:

sauvegarder(contacts)

print(f"Contact '{nom}' supprimé ")

def lister_contacts():

contacts = charger()

if not contacts:

print("Carnet vide.")

return
print(f"\n{'Nom':<20} {'Téléphone':<15} {'Email'}")

print("─" * 55)

for c in sorted(contacts, key=lambda x: x["nom"]):

print(f"{c['nom']:<20} {c['tel']:<15} {c['email']}")

# Test

ajouter_contact("Mathis", "06 12 34 56 78", "mathis@[Link]")

ajouter_contact("Alice", "07 98 76 54 32", "alice@[Link]")

lister_contacts()

rechercher_contact("mat")

supprimer_contact("Alice")

Chapitre 12 — tkinter — Interfaces graphiques

tkinter est la bibliothèque GUI incluse avec Python. Elle permet de créer des fenêtres,
boutons, champs de texte, etc.

12.1 Fenêtre de base et widgets essentiels

python

import tkinter as tk

# Créer la fenêtre principale

fenetre = [Link]()

[Link]("Ma première fenêtre")

[Link]("400x300") # largeur x hauteur

[Link](False, False) # non redimensionnable

# Label — texte statique

label = [Link](fenetre, text="Bonjour !", font=("Arial", 16), fg="blue")


[Link](pady=20)

# Button — bouton cliquable

def au_clic():

[Link](text="Bouton cliqué !")

bouton = [Link](fenetre, text="Clique-moi", command=au_clic,

bg="#2E75B6", fg="white", font=("Arial", 12))

[Link](pady=10)

# Entry — champ de saisie

champ = [Link](fenetre, font=("Arial", 12), width=25)

[Link](pady=10)

def afficher_saisie():

texte = [Link]()

[Link](text=f"Tu as écrit : {texte}")

[Link](fenetre, text="Afficher", command=afficher_saisie).pack()

# Lancer la boucle d'événements (TOUJOURS en dernier)

[Link]()

12.2 Les gestionnaires de disposition

python

import tkinter as tk

fenetre = [Link]()
[Link]("400x250")

# ── pack ── (simple, empile les widgets)

[Link](fenetre, text="pack → haut").pack(side="top", pady=5)

[Link](fenetre, text="pack → bas").pack(side="bottom", pady=5)

[Link](fenetre, text="pack → gauche").pack(side="left", padx=5)

[Link](fenetre, text="pack → droite").pack(side="right", padx=5)

# ── grid ── (grille ligne/colonne, le plus flexible)

frame = [Link](fenetre)

[Link]()

[Link](frame, text="Nom :").grid(row=0, column=0, sticky="e", padx=5, pady=5)

[Link](frame).grid(row=0, column=1, padx=5)

[Link](frame, text="Email :").grid(row=1, column=0, sticky="e", padx=5, pady=5)

[Link](frame).grid(row=1, column=1, padx=5)

[Link](frame, text="Valider").grid(row=2, column=0, columnspan=2, pady=10)

[Link]()

12.3 Variables tkinter et widgets avancés

python

import tkinter as tk

from tkinter import ttk, messagebox, filedialog

fenetre = [Link]()
[Link]("Widgets avancés")

[Link]("450x400")

# Variables tkinter (liées automatiquement aux widgets)

nom_var = [Link](value="Mathis")

age_var = [Link](value=20)

accord = [Link](value=False)

choix = [Link](value="Python")

# Entry lié à une StringVar

[Link](fenetre, text="Nom :").pack()

[Link](fenetre, textvariable=nom_var).pack()

# Scale (curseur)

[Link](fenetre, text="Âge :").pack()

[Link](fenetre, variable=age_var, from_=0, to=100,

orient="horizontal", length=300).pack()

# Checkbutton

[Link](fenetre, text="J'accepte les CGU",

variable=accord).pack(pady=5)

# Combobox (liste déroulante)

[Link](fenetre, text="Langage préféré :").pack()

combo = [Link](fenetre, textvariable=choix,

values=["Python", "JavaScript", "C++", "Rust"])

[Link]()
def valider():

if not [Link]():

[Link]("Attention", "Accepte les CGU d'abord !")

return

[Link]("Résultat",

f"Nom : {nom_var.get()}\nÂge : {age_var.get()}\nLangage : {[Link]()}")

[Link](fenetre, text="Valider", command=valider,

bg="green", fg="white").pack(pady=15)

# Boîtes de dialogue

def ouvrir_fichier():

fichier = [Link](

title="Choisir un fichier",

filetypes=[("Fichiers texte", "*.txt"), ("Tous", "*.*")]

if fichier:

print(f"Fichier choisi : {fichier}")

[Link](fenetre, text="Ouvrir fichier...", command=ouvrir_fichier).pack()

[Link]()

Exercice 13 — Mini calculatrice graphique

Crée une calculatrice avec tkinter qui :

• Affiche un écran (Label ou Entry en lecture seule)

• A des boutons 0–9, +, −, ×, ÷, =, C

• Gère les erreurs (division par zéro)


• A un design soigné avec des couleurs différentes pour les opérateurs

Solution :

python

import tkinter as tk

fenetre = [Link]()

[Link]("Calculatrice")

[Link]("320x420")

[Link](False, False)

[Link](bg="#1e1e2e")

expression = [Link](value="")

# Écran

ecran = [Link](

fenetre, textvariable=expression, font=("Arial", 22),

justify="right", bd=0, bg="#313244", fg="white",

insertbackground="white", relief="flat"

[Link](fill="x", padx=15, pady=(20, 10), ipady=12)

def appuyer(valeur):

[Link]([Link]() + str(valeur))

def effacer():

[Link]("")

def calculer():
try:

expr = [Link]().replace("×", "*").replace("÷", "/")

resultat = eval(expr)

# Éviter l'affichage de .0 inutile

if isinstance(resultat, float) and resultat.is_integer():

resultat = int(resultat)

[Link](resultat)

except ZeroDivisionError:

[Link]("Erreur : div/0")

except Exception:

[Link]("Erreur")

# Disposition des boutons

boutons = [

["C", "←", "%", "÷"],

["7", "8", "9", "×"],

["4", "5", "6", "−"],

["1", "2", "3", "+"],

["±", "0", ".", "="],

couleurs = {

"=": ("#2E75B6", "white"),

"C": ("#e06c75", "white"),

"←": ("#e06c75", "white"),

"÷": ("#fab387", "#1e1e2e"),

"×": ("#fab387", "#1e1e2e"),

"−": ("#fab387", "#1e1e2e"),


"+": ("#fab387", "#1e1e2e"),

"%": ("#a6e3a1", "#1e1e2e"),

"±": ("#a6e3a1", "#1e1e2e"),

frame_boutons = [Link](fenetre, bg="#1e1e2e")

frame_boutons.pack(padx=15, pady=5, fill="both", expand=True)

for ligne in boutons:

frame_ligne = [Link](frame_boutons, bg="#1e1e2e")

frame_ligne.pack(fill="x", pady=3)

for label in ligne:

bg, fg = [Link](label, ("#45475a", "white"))

if label == "←":

cmd = lambda: [Link]([Link]()[:-1])

elif label == "±":

def cmd():

try:

[Link](str(-float([Link]())))

except: pass

elif label == "C":

cmd = effacer

elif label == "=":

cmd = calculer

else:

cmd = lambda v=label: appuyer(v)


[Link](

frame_ligne, text=label, font=("Arial", 16, "bold"),

bg=bg, fg=fg, bd=0, relief="flat", cursor="hand2",

activebackground=bg, activeforeground=fg,

command=cmd, width=5, height=2

).pack(side="left", padx=3, expand=True)

[Link]()

Chapitre 13 — threading — Exécution parallèle

Par défaut Python exécute le code ligne par ligne (séquentiel). Le threading permet de lancer
plusieurs tâches en même temps.

13.1 Créer et lancer un thread

python

import threading

import time

def tache(nom, duree):

print(f"[{nom}] Démarrage...")

[Link](duree) # simule un travail

print(f"[{nom}] Terminé après {duree}s")

# ── Sans threading : séquentiel (total ≈ 6s) ──

tache("A", 2)

tache("B", 3)

tache("C", 1)
# ── Avec threading : parallèle (total ≈ 3s) ──

t1 = [Link](target=tache, args=("A", 2))

t2 = [Link](target=tache, args=("B", 3))

t3 = [Link](target=tache, args=("C", 1))

[Link]()

[Link]()

[Link]()

# join() → attendre la fin d'un thread avant de continuer

[Link]()

[Link]()

[Link]()

print("Tous les threads sont terminés !")

13.2 Threads en tant que classe

python

import threading

import time

class TacheThread([Link]):

def __init__(self, nom, duree):

super().__init__()

[Link] = nom

[Link] = duree
def run(self): # s'exécute quand on appelle .start()

print(f"[{[Link]}] Démarrage")

[Link]([Link])

print(f"[{[Link]}] Fini !")

threads = [TacheThread(f"Thread-{i}", i) for i in range(1, 5)]

for t in threads:

[Link]()

for t in threads:

[Link]()

print("Tout est terminé.")

13.3 Le problème des ressources partagées — Lock

Quand plusieurs threads accèdent à la même variable, des conflits peuvent apparaître (race
condition). Le Lock garantit qu'un seul thread accède à la ressource à la fois.

python

import threading

compteur = 0

lock = [Link]()

def incrementer(n):

global compteur

for _ in range(n):
with lock: # un seul thread à la fois dans ce bloc

compteur += 1

threads = [[Link](target=incrementer, args=(100000,)) for _ in range(5)]

for t in threads: [Link]()

for t in threads: [Link]()

print(f"Compteur final : {compteur}") # doit afficher 500000

# Sans lock → résultat aléatoire et incorrect !

13.4 Partager des données entre threads — Queue

La Queue est la façon propre de faire communiquer des threads sans conflit.

python

import threading

import queue

import time

import random

file = [Link]()

def producteur(nb_items):

for i in range(nb_items):

item = f"item_{i}"

[Link](item)

print(f"Produit : {item}")

[Link]([Link](0.1, 0.3))

[Link](None) # signal de fin


def consommateur():

while True:

item = [Link]()

if item is None:

break

print(f" ↳ Consommé : {item}")

[Link]([Link](0.2, 0.5))

file.task_done()

t_prod = [Link](target=producteur, args=(6,))

t_cons = [Link](target=consommateur)

t_prod.start()

t_cons.start()

t_prod.join()

t_cons.join()

print("Pipeline terminé ")

13.5 Threading + tkinter — Interface non bloquante

C'est le cas d'usage le plus courant : lancer une tâche longue sans geler l'interface.

python

import tkinter as tk

import threading

import time

fenetre = [Link]()

[Link]("Threading + tkinter")
[Link]("350x200")

label = [Link](fenetre, text="Prêt.", font=("Arial", 14))

[Link](pady=20)

barre = [Link](fenetre, text="", font=("Arial", 20))

[Link]()

def tache_longue():

for i in range(1, 11):

[Link](0.5)

# Mettre à jour l'UI depuis un thread → utiliser after() ou StringVar

[Link](0, lambda i=i: [Link](

text=f"Traitement... {i * 10}%"

))

[Link](0, lambda i=i: [Link](

text="█" * i + "░" * (10 - i)

))

[Link](0, lambda: [Link](text="Terminé "))

[Link](0, lambda: [Link](state="normal"))

def lancer():

[Link](state="disabled")

[Link](text="Démarrage...")

t = [Link](target=tache_longue, daemon=True)

[Link]()

bouton = [Link](fenetre, text="Lancer la tâche",


command=lancer, bg="#2E75B6", fg="white",

font=("Arial", 12))

[Link](pady=15)

[Link]()

Ne jamais modifier les widgets tkinter directement depuis un thread. Toujours utiliser
[Link](0, callback) qui remet la mise à jour dans le thread principal.

Exercice 14 — Téléchargeur simulé avec interface

Crée une application tkinter qui :

1. Affiche une liste de 5 "fichiers" à télécharger (noms + tailles fictives).

2. Un bouton "Tout télécharger" lance les téléchargements en parallèle (threads).

3. Chaque fichier a sa propre barre de progression (Label texte).

4. Un label global indique quand tout est terminé.

Solution :

python

import tkinter as tk

import threading

import time

import random

FICHIERS = [

("rapport_annuel.pdf", 2.4),

("video_cours.mp4", 15.7),

("[Link]", 5.1),

("musique.mp3", 3.8),

("[Link]", 9.2),

]
fenetre = [Link]()

[Link]("Téléchargeur")

[Link]("450x370")

[Link](bg="#1e1e2e")

[Link](fenetre, text="Téléchargeur de fichiers",

font=("Arial", 15, "bold"), bg="#1e1e2e", fg="white").pack(pady=10)

barres = {} # {nom: (label_nom, label_barre, label_pct)}

frame = [Link](fenetre, bg="#1e1e2e")

[Link](fill="x", padx=20)

for nom, taille in FICHIERS:

f = [Link](frame, bg="#313244", pady=6)

[Link](fill="x", pady=3)

[Link](f, text=f"{nom} ({taille} Mo)",

bg="#313244", fg="#cdd6f4", font=("Arial", 10), width=35,

anchor="w").pack(side="left", padx=8)

lbl_barre = [Link](f, text="░"*20, bg="#313244",

fg="#6c7086", font=("Courier", 10))

lbl_barre.pack(side="left")

lbl_pct = [Link](f, text=" 0%", bg="#313244",

fg="#6c7086", font=("Arial", 10), width=5)

lbl_pct.pack(side="left")

barres[nom] = (lbl_barre, lbl_pct)


statut = [Link](fenetre, text="", font=("Arial", 11),

bg="#1e1e2e", fg="#a6e3a1")

[Link](pady=8)

def telecharger(nom, taille):

etapes = 20

for i in range(1, etapes + 1):

# Simuler une vitesse variable

[Link](taille / etapes * [Link](0.05, 0.15))

rempli = "█" * i + "░" * (etapes - i)

pct = f"{i * 5}%"

lbl_barre, lbl_pct = barres[nom]

[Link](0, lambda b=rempli, lb=lbl_barre: [Link](

text=b, fg="#89b4fa"))

[Link](0, lambda p=pct, lp=lbl_pct: [Link](

text=f" {p}", fg="#89b4fa"))

# Marquer comme terminé

[Link](0, lambda lb=barres[nom][0]: [Link](fg="#a6e3a1"))

[Link](0, lambda lp=barres[nom][1]: [Link](fg="#a6e3a1"))

def tout_telecharger():

[Link](state="disabled")

[Link](text="Téléchargement en cours...", fg="#f9e2af")

threads = []

for nom, taille in FICHIERS:

t = [Link](target=telecharger, args=(nom, taille), daemon=True)

[Link](t)

[Link]()
def attendre():

for t in threads:

[Link]()

[Link](0, lambda: [Link](

text="Tous les fichiers téléchargés ", fg="#a6e3a1"))

[Link](target=attendre, daemon=True).start()

bouton = [Link](fenetre, text="⬇ Tout télécharger",

command=tout_telecharger, font=("Arial", 12, "bold"),

bg="#2E75B6", fg="white", bd=0, padx=15, pady=8,

cursor="hand2", activebackground="#1a5a9e")

[Link](pady=5)

[Link]()

Récapitulatif — Les 4 modules

Module Utilité principale Fonctions clés

os Système de fichiers, chemins, env getcwd, listdir, walk, [Link], makedirs

json Sérialisation, config, API load, dump, loads, dumps

tkinter Interfaces graphiques Tk, Label, Button, Entry, mainloop

threading Parallélisme, UI non bloquante Thread, Lock, Queue, start, join

Prochaines étapes naturelles depuis ces modules :

• pathlib → alternative moderne et orientée objet à [Link]

• requests → HTTP et API REST (JSON en pratique réelle)


• [Link] + thèmes → UI plus moderne

• asyncio → alternative au threading pour les tâches I/O

Peut tu ajouter socket

08:59

Chapitre 14 — Le module socket — Communication réseau

Les sockets permettent à deux programmes de communiquer via le réseau, que ce soit sur la
même machine ou entre deux ordinateurs distants. C'est la base de tout ce qui tourne sur
internet : HTTP, FTP, SSH, etc.

14.1 Comprendre les sockets

┌─────────────────┐ réseau ┌─────────────────┐

│ CLIENT │ ──────────────────► │ SERVEUR │

│ │ ◄────────────────── │ │

│ [Link] │ TCP/IP │ [Link] │

│ [Link] │ │ [Link] │

│ [Link] │ │ [Link] │

└─────────────────┘ └─────────────────┘

Deux protocoles principaux :

• TCP (SOCK_STREAM) — fiable, ordonné, avec accusé de réception. Utilisé pour HTTP,
SSH, FTP.

• UDP (SOCK_DGRAM) — rapide, sans connexion, sans garantie. Utilisé pour le


streaming, les jeux en ligne.

14.2 Serveur TCP minimal

python

import socket

# Créer le socket

serveur = [Link](socket.AF_INET, # IPv4


socket.SOCK_STREAM) # TCP

# Évite l'erreur "Address already in use" au redémarrage

[Link](socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# Associer à une adresse et un port

[Link](("localhost", 12345))

# Écouter (max 5 connexions en attente)

[Link](5)

print("Serveur en écoute sur le port 12345...")

# Accepter une connexion

client_socket, adresse = [Link]()

print(f"Connexion de {adresse}")

# Recevoir des données (max 1024 octets)

donnees = client_socket.recv(1024)

print(f"Reçu : {[Link]('utf-8')}")

# Répondre

client_socket.send("Message bien reçu !".encode("utf-8"))

# Fermer

client_socket.close()

[Link]()

14.3 Client TCP minimal


python

import socket

# Créer le socket

client = [Link](socket.AF_INET, socket.SOCK_STREAM)

# Se connecter au serveur

[Link](("localhost", 12345))

# Envoyer un message (toujours encoder en bytes)

[Link]("Bonjour serveur !".encode("utf-8"))

# Recevoir la réponse

reponse = [Link](1024)

print(f"Réponse : {[Link]('utf-8')}")

# Fermer

[Link]()

Les sockets transmettent des bytes, pas des strings. Il faut toujours .encode("utf-8") pour
envoyer et .decode("utf-8") pour recevoir.

14.4 Serveur multi-clients avec threading

Un serveur réel doit gérer plusieurs clients simultanément. On utilise un thread par client.

python

import socket

import threading

def gerer_client(conn, adresse):


print(f"[+] Nouveau client : {adresse}")

try:

while True:

donnees = [Link](1024)

if not donnees:

break # client déconnecté

message = [Link]("utf-8")

print(f"[{adresse}] → {message}")

# Renvoyer le message en majuscules (echo transformé)

reponse = f"ECHO : {[Link]()}"

[Link]([Link]("utf-8"))

except ConnectionResetError:

print(f"[!] {adresse} s'est déconnecté brutalement.")

finally:

[Link]()

print(f"[-] {adresse} déconnecté.")

def lancer_serveur(hote="localhost", port=12345):

serveur = [Link](socket.AF_INET, socket.SOCK_STREAM)

[Link](socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

[Link]((hote, port))

[Link](10)

print(f"Serveur démarré sur {hote}:{port}")

print("En attente de connexions... (Ctrl+C pour arrêter)\n")


try:

while True:

conn, adresse = [Link]()

# Un thread par client

t = [Link](

target=gerer_client,

args=(conn, adresse),

daemon=True

[Link]()

print(f"Threads actifs : {threading.active_count() - 1}")

except KeyboardInterrupt:

print("\nServeur arrêté.")

finally:

[Link]()

lancer_serveur()

14.5 Client interactif

python

import socket

import threading

def recevoir(sock):

"""Thread dédié à la réception des messages."""


while True:

try:

msg = [Link](1024).decode("utf-8")

if not msg:

print("Connexion fermée par le serveur.")

break

print(f"\r{msg}\nToi > ", end="", flush=True)

except:

break

def lancer_client(hote="localhost", port=12345):

client = [Link](socket.AF_INET, socket.SOCK_STREAM)

try:

[Link]((hote, port))

print(f"Connecté à {hote}:{port}")

print("Tape 'quit' pour quitter.\n")

except ConnectionRefusedError:

print("Impossible de se connecter. Le serveur est-il lancé ?")

return

# Thread de réception en arrière-plan

t = [Link](target=recevoir, args=(client,), daemon=True)

[Link]()

# Boucle d'envoi

try:

while True:
msg = input("Toi > ")

if [Link]() == "quit":

break

if msg:

[Link]([Link]("utf-8"))

except KeyboardInterrupt:

pass

finally:

[Link]()

print("Déconnecté.")

lancer_client()

14.6 Envoyer des données structurées — JSON sur socket

En pratique, on envoie rarement du texte brut. On envoie du JSON pour structurer les
données, mais il faut gérer la délimitation des messages (un recv peut recevoir plusieurs
messages à la fois ou un message en plusieurs morceaux).

La solution la plus simple : préfixer chaque message par sa longueur sur 4 octets.

python

import socket

import json

import struct

def envoyer_json(sock, data):

"""Envoie un objet Python comme JSON, préfixé par sa longueur."""

message = [Link](data, ensure_ascii=False).encode("utf-8")

# [Link](">I", n) → 4 octets big-endian représentant n

longueur = [Link](">I", len(message))


[Link](longueur + message)

def recevoir_json(sock):

"""Reçoit un message JSON complet et retourne l'objet Python."""

# Lire exactement 4 octets de longueur

raw_len = recvall(sock, 4)

if not raw_len:

return None

longueur = [Link](">I", raw_len)[0]

# Lire exactement `longueur` octets

raw_data = recvall(sock, longueur)

return [Link](raw_data.decode("utf-8"))

def recvall(sock, n):

"""Reçoit exactement n octets (plusieurs recv si nécessaire)."""

data = b""

while len(data) < n:

paquet = [Link](n - len(data))

if not paquet:

return None

data += paquet

return data

# ── Exemple d'utilisation côté serveur ──

def gerer_client_json(conn, adresse):

print(f"[+] {adresse} connecté")


while True:

data = recevoir_json(conn)

if not data:

break

print(f"[{adresse}] reçu : {data}")

# Répondre avec un objet structuré

reponse = {

"statut": "ok",

"echo": data,

"traite": True

envoyer_json(conn, reponse)

[Link]()

print(f"[-] {adresse} déconnecté")

14.7 Socket UDP

UDP est sans connexion et plus rapide. Parfait pour les données en temps réel où on peut se
permettre de perdre quelques paquets.

python

import socket

# ── Serveur UDP ──

def serveur_udp(port=9999):

sock = [Link](socket.AF_INET, socket.SOCK_DGRAM)

[Link](("localhost", port))

print(f"Serveur UDP sur le port {port}")


while True:

donnees, adresse = [Link](1024) # pas d'accept() en UDP !

msg = [Link]("utf-8")

print(f"[{adresse}] {msg}")

[Link](f"Reçu : {msg}".encode("utf-8"), adresse)

# ── Client UDP ──

def client_udp(port=9999):

sock = [Link](socket.AF_INET, socket.SOCK_DGRAM)

for i in range(5):

msg = f"Paquet UDP n°{i}"

[Link]([Link]("utf-8"), ("localhost", port)) # pas de connect()

reponse, _ = [Link](1024)

print(f"Réponse : {[Link]('utf-8')}")

[Link]()

14.8 Gestionnaire de contexte et bonnes pratiques

python

import socket

# ── Utiliser with pour fermeture automatique ──

with [Link](socket.AF_INET, socket.SOCK_STREAM) as client:

[Link](("localhost", 12345))
[Link]("Bonjour !".encode("utf-8"))

reponse = [Link](1024)

print([Link]("utf-8"))

# socket fermé automatiquement ici, même en cas d'erreur

# ── Timeout : ne pas bloquer indéfiniment ──

with [Link](socket.AF_INET, socket.SOCK_STREAM) as sock:

[Link](5.0) # lève [Link] après 5 secondes

try:

[Link](("[Link]", 80))

[Link](b"GET / HTTP/1.0\r\nHost: [Link]\r\n\r\n")

reponse = [Link](4096)

print(reponse[:200])

except [Link]:

print("Timeout : le serveur ne répond pas.")

except ConnectionRefusedError:

print("Connexion refusée.")

except [Link] as e:

print(f"Erreur DNS : {e}")

# ── Trouver un port libre automatiquement ──

def trouver_port_libre():

with [Link](socket.AF_INET, socket.SOCK_STREAM) as s:

[Link](("", 0))

return [Link]()[1]

port = trouver_port_libre()

print(f"Port libre trouvé : {port}")


# ── Obtenir l'IP locale et le hostname ──

hostname = [Link]()

ip_locale = [Link](hostname)

print(f"Machine : {hostname} ({ip_locale})")

Exercice 15 — Chat en réseau

Crée une application de chat en temps réel entre plusieurs clients :

Serveur :

• Accepte plusieurs clients simultanément (threads)

• Chaque client envoie son pseudo à la connexion

• Quand un client envoie un message, le serveur le diffuse à tous les autres (broadcast)

• Affiche [pseudo] a rejoint le chat et [pseudo] a quitté le chat

Client :

• Demande le pseudo au démarrage

• Thread dédié à la réception (affichage en temps réel)

• Thread principal pour la saisie et l'envoi

• Commande /quit pour se déconnecter proprement

Solution — Serveur :

python

import socket

import threading

clients = {} # {socket: pseudo}

lock_cli = [Link]()

def broadcast(message, expediteur=None):

"""Envoie un message à tous les clients sauf l'expéditeur."""


with lock_cli:

for sock in list(clients):

if sock != expediteur:

try:

[Link]([Link]("utf-8"))

except:

[Link]()

del clients[sock]

def gerer_client(conn, adresse):

try:

# Premier message = pseudo

pseudo = [Link](1024).decode("utf-8").strip()

with lock_cli:

clients[conn] = pseudo

print(f"[+] {pseudo} ({adresse})")

broadcast(f"★ {pseudo} a rejoint le chat !", expediteur=conn)

[Link]("Bienvenue ! Tape /quit pour partir.\n".encode("utf-8"))

while True:

msg = [Link](1024).decode("utf-8").strip()

if not msg or msg == "/quit":

break

print(f"[{pseudo}] {msg}")

broadcast(f"[{pseudo}] {msg}", expediteur=conn)

except (ConnectionResetError, ConnectionAbortedError):


pass

finally:

pseudo = [Link](conn, "Inconnu")

with lock_cli:

if conn in clients:

del clients[conn]

[Link]()

print(f"[-] {pseudo} déconnecté")

broadcast(f"★ {pseudo} a quitté le chat.")

def lancer_serveur(port=5555):

serveur = [Link](socket.AF_INET, socket.SOCK_STREAM)

[Link](socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

[Link](("localhost", port))

[Link](10)

print(f"Serveur chat sur le port {port}\n")

try:

while True:

conn, adresse = [Link]()

[Link](target=gerer_client,

args=(conn, adresse), daemon=True).start()

except KeyboardInterrupt:

print("\nServeur arrêté.")

finally:

[Link]()
lancer_serveur()

Solution — Client :

python

import socket

import threading

def recevoir(sock):

while True:

try:

msg = [Link](1024).decode("utf-8")

if not msg:

print("\nDéconnecté du serveur.")

break

print(f"\r{msg}")

print(f"Toi > ", end="", flush=True)

except:

break

def lancer_client(port=5555):

sock = [Link](socket.AF_INET, socket.SOCK_STREAM)

try:

[Link](("localhost", port))

except ConnectionRefusedError:

print("Serveur introuvable. Lance le serveur d'abord !")

return

pseudo = input("Ton pseudo : ").strip()


[Link]([Link]("utf-8"))

[Link](target=recevoir, args=(sock,), daemon=True).start()

try:

while True:

msg = input("Toi > ").strip()

if not msg:

continue

[Link]([Link]("utf-8"))

if msg == "/quit":

break

except KeyboardInterrupt:

[Link]("/quit".encode("utf-8"))

finally:

[Link]()

print("Déconnecté.")

lancer_client()

Pour tester : lance [Link] dans un terminal, puis lance [Link] dans plusieurs autres
terminaux simultanément.

Récapitulatif — socket

Concept Rôle

socket() Créer un socket TCP ou UDP

bind() Associer à une adresse + port (serveur)

listen() / accept() Attendre et accepter une connexion TCP


Concept Rôle

connect() Se connecter à un serveur (client)

send() / recv() Envoyer / recevoir des bytes

sendall() Envoyer garantissant l'envoi complet

sendto() / recvfrom() Envoyer / recevoir en UDP (sans connexion)

close() Fermer la connexion

settimeout() Définir un délai d'attente maximum

[Link] Un thread par client pour le multi-client

[Link] Préfixer la longueur pour les messages JSON

Vous aimerez peut-être aussi