Cours débutant · 4 séances de 60 à 90 min
Ce que fait le PC
quand Python s’exécute.
Comprendre le matériel, la mémoire et le parcours d’un programme, avec des exemples Python.
Prérequis : savoir ouvrir un terminal. Les bases Python utiles sont expliquées dans le cours.
Mode d’emploi du cours
Les flèches gauche et droite changent de diapositive. Le sommaire permet de choisir un sujet. « Vue complète » affiche tout le cours. Les notes et corrections se déplient au clic. Le bouton Imprimer permet de produire un PDF. Les exemples s’exécutent dans Python sur votre ordinateur, pas dans cette page.
Le parcours
Quatre séances pour relier le code au matériel
- Le PC
Composants, binaire, mémoire et connexions. - Python en action
Code source, bytecode, interpréteur et système. - Les données
Objets, références, fichiers et performances. - Le laboratoire
Expériences, quiz et exercice de synthèse.
Objectifs et organisation
À la fin, vous devez pouvoir expliquer le rôle du CPU, distinguer RAM et stockage, décrire la compilation dans CPython et suivre une lecture de fichier. Prévoir un PC avec Python 3 pour les exercices. Le cours décrit le fonctionnement habituel de CPython, l’implémentation de Python la plus courante. Certaines autres implémentations et configurations utilisent des mécanismes différents.
01 / Matériel
Les pièces du PC
| Composant | Fonction | Lien avec Python |
|---|---|---|
| CPU | Exécuter des instructions machine | Faire fonctionner l’interpréteur |
| RAM | Conserver les données de travail | Accueillir les objets et le code |
| SSD | Conserver les fichiers | Stocker Python et vos fichiers .py |
| Carte mère | Relier les composants | Permettre leurs échanges |
| GPU | Rendu graphique et calcul parallèle | Calculs via des bibliothèques adaptées |
Alimentation, refroidissement et GPU
L’alimentation fournit l’énergie. Le refroidissement évacue la chaleur et aide à maintenir les performances. Un programme Python ordinaire ne délègue pas automatiquement ses calculs au GPU. Une bibliothèque et un environnement compatibles doivent organiser ce travail.
01 / Matériel
Stocker n’est pas travailler en mémoire
SSD : les fichiers
Votre fichier bonjour.py reste disponible après l’arrêt du PC.
Le SSD conserve aussi l’installation de Python.
RAM : le travail en cours
Le processus Python utilise la RAM pour ses instructions et ses objets.
Son contenu disparaît à la coupure de l’alimentation.
Une variable Python ne devient pas un fichier tant que le programme ne l’enregistre pas.
Question à poser au groupe
« Si je ferme Python, ma liste de courses existe-t-elle encore ? » Réponse : pas automatiquement. Une liste créée en mémoire cesse d’être accessible à la fermeture du processus. Pour la retrouver, il faut par exemple l’écrire dans un fichier.
01 / Matériel
Les données deviennent des bits
forment un octet. Un octet permet de représenter 256 combinaisons.
Le sens de ces bits dépend du format utilisé.
print(bin(5))
# 0b101
print(format(5, "08b"))
# 00000101
print("é".encode("utf-8"))
# b'\xc3\xa9'Caractères, octets et entiers Python
Le caractère « é » occupe ici deux octets en UTF-8. Un caractère ne correspond donc pas toujours à un octet. La représentation binaire affichée par bin(5) décrit la valeur 5, pas toute la mémoire occupée par l’objet entier Python. Cet objet comporte aussi des informations de gestion.
01 / Matériel
Le CPU exécute des instructions machine
- Il récupère une instruction.
- Il décode l’opération demandée.
- Il réalise le calcul, l’accès mémoire ou le changement de chemin.
Les registres accueillent de petites quantités de données directement utilisées par les instructions.
Un modèle simplifié
Les processeurs modernes font progresser plusieurs instructions à la fois, anticipent des branchements et réorganisent des opérations. Une fréquence de 3 GHz signifie environ trois milliards de cycles par seconde, pas nécessairement trois milliards d’instructions. x86-64 et ARM64 désignent des architectures avec des jeux d’instructions différents.
01 / Matériel
Les données circulent dans une hiérarchie
| Niveau | Usage | Proximité du calcul |
|---|---|---|
| Registres | Valeurs directement manipulées | Dans le cœur du CPU |
| Caches L1, L2, L3 | Instructions et données récemment utilisées | Proches des cœurs |
| RAM | Mémoire de travail du processus | Accès via le contrôleur mémoire |
| SSD | Fichiers persistants | Accès par les entrées/sorties |
Attendre les données peut coûter plus de temps que les calculer.
Ce que les caches accélèrent
Les caches matériels conservent des blocs de mémoire. Ils exploitent la réutilisation des données et la proximité de leurs adresses. Ils sont distincts du cache .pyc de Python et du cache de fichiers du système. On évite ici des latences chiffrées universelles : elles dépendent fortement du matériel et de la charge.
01 / Matériel
Les connexions transportent commandes et données
| Connexion | Exemple d’échange |
|---|---|
| Canaux mémoire | Le contrôleur mémoire échange avec la RAM. |
| PCI Express | Un SSD NVMe ou une carte graphique échange avec le système. |
| USB | Le clavier transmet un événement à son contrôleur. |
Un échange identifie une opération, sa destination et les données concernées.
Transferts et interruptions
Certains périphériques transfèrent des données vers ou depuis la RAM par DMA, sous le contrôle du système. Le CPU n’a pas à copier chaque octet lui-même. Un périphérique peut signaler un événement par une interruption. Les chemins exacts varient selon la carte mère et les contrôleurs.
02 / Exécution
Le système organise l’accès au PC
Un processus Python
Le système lui fournit un espace mémoire et des ressources.
Un thread est un flux d’exécution auquel le système attribue du temps CPU.
Des services partagés
Le système gère les fichiers et les périphériques grâce aux pilotes.
Il protège les processus les uns des autres.
Mémoire virtuelle
Le programme manipule généralement des adresses virtuelles. Le matériel et le système les traduisent vers la mémoire physique. Une identité d’objet obtenue avec id() ne doit pas être interprétée comme une adresse physique dans une barrette de RAM.
02 / Exécution
Notre premier programme
# fichier bonjour.py
a = 5
b = 3
resultat = a + b
print(resultat)= associe un nom à un objet.
+ demande une addition ici.
print() écrit une représentation du résultat sur la sortie standard.
Dans le terminal, depuis le dossier du fichier :
python bonjour.py
# Résultat attendu : 8Préparation de l’environnement
Vérifier l’installation avec python --version. Sous Windows, le lanceur py peut remplacer python. Sur certains systèmes, utiliser python3. Choisir la commande qui désigne votre installation Python 3. Un éditeur sert à écrire le fichier, le terminal sert à lancer les commandes. Le bouton d’exécution d’un éditeur organise généralement ces opérations pour vous.
02 / Exécution
Python passe aussi par une compilation
- Source .py : le texte que vous écrivez.
- Compilation : CPython analyse le code et produit du bytecode.
- Interprétation : CPython réalise les opérations du bytecode.
- Matériel : le CPU exécute les instructions machine de l’interpréteur et des bibliothèques.
Portée de ce modèle et source
Ce parcours décrit le fonctionnement usuel de CPython. Des moteurs JIT ou d’autres implémentations peuvent produire du code machine pendant l’exécution. Le bytecode reste une représentation interne, distincte des instructions du CPU. Documentation Python : bytecode.
02 / Exécution
Trois niveaux de code
| Niveau | Destinataire | Exemple |
|---|---|---|
| Code Python | Environnement Python | return a + b |
| Bytecode CPython | Interpréteur CPython | Charger les valeurs, effectuer l’opération, retourner |
| Code machine | CPU x86-64, ARM64… | Instructions binaires de l’interpréteur installé |
Une ligne Python peut provoquer de nombreuses instructions machine.
Pourquoi autant d’instructions ?
Python doit notamment déterminer les objets concernés, appliquer les opérations adaptées à leurs types et gérer les références. L’addition de deux entiers et la concaténation de deux chaînes utilisent le même symbole +, mais ne réalisent pas le même travail.
02 / Exécution
Observer le bytecode avec dis
import dis
def addition(a, b):
return a + b
dis.dis(addition)
print(addition(5, 3))La sortie décrit les instructions de la fonction.
On y repère le chargement des paramètres, l’opération et le retour du résultat.
Les noms et l’organisation des instructions varient selon la version.
Exercice et correction
Remplacer + par * puis comparer la sortie. La fonction demande une multiplication, l’opération correspondante change. dis n’affiche pas le code machine du CPU. Nous utilisons des paramètres plutôt que 5 + 3 dans la fonction afin d’éviter qu’une simple expression constante masque l’opération lors de la compilation. Documentation du module dis.
02 / Exécution
Le rôle du dossier __pycache__
Lors de l’importation d’un module, CPython peut enregistrer un cache de bytecode dans un fichier .pyc.
python -m py_compile bonjour.pyCette commande prépare explicitement un fichier compilé sans exécuter le programme.
Un .pyc peut éviter de recompiler le source. Il n’accélère pas à lui seul les calculs du programme.
Nuances et source
Le nom du fichier contient généralement une indication de version. Le cache dépend de l’environnement Python et doit être valide pour être réutilisé. L’exécution directe d’un script principal ne crée pas systématiquement un .pyc pour ce script. Un fichier .pyc n’est pas un exécutable natif autonome. Documentation : fichiers Python compilés.
02 / Exécution
Le parcours de print(8)
- CPython prépare une représentation textuelle de l’objet.
- Il l’écrit dans la sortie standard, éventuellement via un tampon.
- Le système transmet cette sortie à sa destination.
- Si la destination est un terminal, celui-ci organise l’affichage.
Une sortie peut aussi être un fichier
print() ne commande pas directement les pixels. La sortie standard peut être redirigée. Selon le terminal et le système, la commande python bonjour.py > resultat.txt envoie la sortie vers un fichier. L’encodage employé peut dépendre de l’environnement.
03 / Données
Les noms font référence à des objets
a = [1, 2]
b = a
b.append(3)
print(a)
# [1, 2, 3]
print(a is b)
# Truea et b désignent la même liste.
append() modifie cette liste.
Une affectation ne copie pas automatiquement l’objet.
Exercice et correction
Remplacer b = a par b = a.copy(). Le résultat affiché pour a devient [1, 2] et a is b devient False. copy() réalise ici une copie superficielle. Des listes imbriquées pourraient encore partager leurs éléments internes.
03 / Données
La taille d’un objet dépend de sa représentation
import sys
print(sys.getsizeof(5))
print(sys.getsizeof([1, 2, 3]))
print(sys.getsizeof("bonjour"))Les valeurs dépendent de l’implémentation, de la version et de la plateforme.
getsizeof() mesure la taille directement attribuée à l’objet. Pour une liste, cela n’additionne pas les tailles de tous ses éléments.
Gestion de la mémoire
CPython gère notamment la durée de vie des objets grâce aux références et à un mécanisme de collecte des cycles. del a supprime une liaison de nom : cela ne garantit pas la disparition immédiate de l’objet ni le retour immédiat de mémoire au système. Le programmeur doit toujours éviter de conserver inutilement de grands ensembles de données.
03 / Données
Lire un fichier mobilise plusieurs couches
with open("message.txt", "w", encoding="utf-8") as fichier:
fichier.write("Bonjour depuis le SSD !")
with open("message.txt", encoding="utf-8") as fichier:
texte = fichier.read()
print(texte)Python demande l’accès au système. Celui-ci utilise son cache de fichiers ou le stockage. Python obtient ensuite le texte en mémoire.
Tampons, persistance et dossier courant
Le fichier est créé dans le dossier courant du programme. Ce code remplace son contenu s’il existe déjà : utiliser un dossier d’exercice. with ferme le fichier et fait vider les tampons Python à la sortie du bloc. Le système peut encore différer l’écriture physique sur le stockage. Une seconde lecture peut provenir de la RAM et ne mesure donc pas forcément la vitesse du SSD.
03 / Données
Le composant limitant dépend du travail
| Situation | Limitation possible | Piste à explorer |
|---|---|---|
| Une longue boucle de calcul | CPU et coût des opérations Python | Algorithme, fonctions adaptées |
| Un fichier énorme lu en une fois | RAM | Lecture progressive |
| Beaucoup de petits fichiers | Entrées/sorties et gestion des fichiers | Réduire les accès répétés |
| Attente d’une réponse web | Réseau ou serveur distant | Concurrence adaptée aux attentes |
Pourquoi mesurer ?
Un CPU plus puissant ne supprime pas une attente réseau. Un SSD plus rapide n’accélère pas forcément un calcul déjà en RAM. Une mesure doit préciser la taille des données, les conditions et les versions utilisées.
03 / Données
Plusieurs cœurs et Python
Le parallélisme nécessite un travail que l’on peut répartir et un programme qui organise cette répartition.
- Avec le GIL actif dans CPython, un seul thread exécute le bytecode Python à la fois dans un interpréteur.
- Des processus séparés peuvent répartir des calculs sur plusieurs cœurs.
- Des bibliothèques natives peuvent libérer le GIL et effectuer leurs propres calculs en parallèle.
Configurations différentes
Des versions de CPython proposent aussi des builds free-threaded, qui peuvent désactiver le GIL. Les comportements dépendent donc de l’installation et des extensions. Les threads restent utiles avec le GIL pour certains travaux qui attendent des entrées/sorties. Créer des tâches et transférer leurs données a aussi un coût. Documentation : GIL.
04 / Laboratoire · 15 min
TP 1 : compiler sans exécuter
source = "print('Le programme s’exécute')"
code = compile(source, "<exercice>", "exec")
print("Compilation terminée")
exec(code)Avant d’exécuter : dans quel ordre les deux messages apparaîtront-ils ?
Correction et prolongement
« Compilation terminée » apparaît avant « Le programme s’exécute ». compile() crée un objet code, exec() l’exécute. Remplacer la chaîne par print( sans parenthèse fermante : la compilation échoue avec SyntaxError. Avec une chaîne contenant print(1 / 0), la compilation réussit mais l’exécution produit ZeroDivisionError. Utiliser uniquement le code d’exercice de confiance avec exec().
04 / Laboratoire · 20 min
TP 2 : mesurer une opération
from timeit import repeat
mesures = repeat(
"sum(range(100_000))",
number=100,
repeat=5,
)
print("Secondes pour 100 calculs :", mesures)
print("Meilleur temps par calcul :", min(mesures) / 100)Comparer avec sum(list(range(100_000))). Quel travail supplémentaire cette version demande-t-elle ?
Correction et interprétation
La deuxième version construit une liste avant de la parcourir, ce qui ajoute une allocation et des références en mémoire. Les temps mesurés peuvent varier : les observations priment sur une prédiction absolue. Une durée mesure un temps écoulé, pas directement un nombre d’instructions CPU. Répéter les mesures limite l’effet de perturbations ponctuelles.
04 / Laboratoire · 15 min
TP 3 : limiter les données en mémoire
from pathlib import Path
chemin = Path("nombres_exercice.txt")
with chemin.open("w", encoding="utf-8") as f:
for n in range(10_000):
f.write(f"{n}\n")
with chemin.open(encoding="utf-8") as f:
total = sum(int(ligne) for ligne in f)
print(total)Consigne et correction
Exécuter dans un dossier d’exercice : le fichier nombres_exercice.txt est créé ou remplacé. Résultat attendu : 49 995 000. La lecture parcourt progressivement les lignes, avec des tampons, sans conserver toutes les valeurs dans une liste. Le générateur fournit les valeurs à sum() au fil du parcours. La consommation mémoire ne croît donc pas comme une liste contenant toutes les lignes.
04 / Vérification
Quel code le CPU exécute-t-il directement ?
Deux questions supplémentaires
1. Un .pyc rend-il automatiquement une boucle plus rapide ? Non, il sert à éviter une recompilation du source lorsque le cache peut être utilisé.
2. Une variable survit-elle à l’arrêt du programme ? Pas automatiquement. Le programme doit sauvegarder les informations à conserver, par exemple dans un fichier.
04 / Synthèse · 20 min
Le trajet complet d’un calcul
with open("nombres_exercice.txt", encoding="utf-8") as f:
valeurs = [int(ligne) for ligne in f]
resultat = sum(valeurs)
print(resultat)Expliquer le rôle du SSD, de la RAM, de CPython, du CPU et du système à chaque étape.
Correction guidée
Le SSD conserve le script et les données. Le système lance le processus et rend le code accessible en mémoire. CPython compile le source puis exécute son bytecode. Le système sert la lecture depuis son cache ou le stockage. Python construit la liste et les objets entiers en mémoire. Le CPU exécute les instructions machine nécessaires à toutes ces opérations, notamment au calcul. print() écrit sur la sortie standard. Remplacer la liste par un générateur réduit les données conservées simultanément.
Référence
Les mots à retenir
| Mot | Définition |
|---|---|
| Instruction machine | Opération que le CPU sait exécuter. |
| Bytecode | Représentation intermédiaire utilisée par CPython. |
| Interpréteur | Programme qui réalise les opérations du programme Python. |
| Processus | Programme en cours d’exécution avec ses ressources. |
| Référence | Lien qui permet de désigner un objet. |
| Entrée/sortie | Échange avec un fichier, un périphérique ou le réseau. |
Pour continuer
Le matériel et Python, ensemble
Le SSD conserve. La RAM accueille le travail. Le CPU exécute. Le système coordonne. CPython donne un sens aux opérations Python.
Vous pouvez maintenant décrire ce qui se passe entre un fichier .py et le résultat affiché.
Documentation officielle
Tutoriel Python · Glossaire · dis · timeit · getsizeof
Le cours fonctionne hors ligne. Les liens de documentation nécessitent Internet. Les détails du bytecode et de la mémoire varient selon l’environnement.