PYTHON / LE PC

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

  1. Le PC
    Composants, binaire, mémoire et connexions.
  2. Python en action
    Code source, bytecode, interpréteur et système.
  3. Les données
    Objets, références, fichiers et performances.
  4. 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

ComposantFonctionLien avec Python
CPUExécuter des instructions machineFaire fonctionner l’interpréteur
RAMConserver les données de travailAccueillir les objets et le code
SSDConserver les fichiersStocker Python et vos fichiers .py
Carte mèreRelier les composantsPermettre leurs échanges
GPURendu graphique et calcul parallèleCalculs 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

8 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

  1. Il récupère une instruction.
  2. Il décode l’opération demandée.
  3. 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

NiveauUsageProximité du calcul
RegistresValeurs directement manipuléesDans le cœur du CPU
Caches L1, L2, L3Instructions et données récemment utiliséesProches des cœurs
RAMMémoire de travail du processusAccès via le contrôleur mémoire
SSDFichiers persistantsAccè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

ConnexionExemple d’échange
Canaux mémoireLe contrôleur mémoire échange avec la RAM.
PCI ExpressUn SSD NVMe ou une carte graphique échange avec le système.
USBLe 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 : 8
Pré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

  1. Source .py : le texte que vous écrivez.
  2. Compilation : CPython analyse le code et produit du bytecode.
  3. Interprétation : CPython réalise les opérations du bytecode.
  4. 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

NiveauDestinataireExemple
Code PythonEnvironnement Pythonreturn a + b
Bytecode CPythonInterpréteur CPythonCharger les valeurs, effectuer l’opération, retourner
Code machineCPU 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.py

Cette 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)

  1. CPython prépare une représentation textuelle de l’objet.
  2. Il l’écrit dans la sortie standard, éventuellement via un tampon.
  3. Le système transmet cette sortie à sa destination.
  4. 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)
# True

a 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

SituationLimitation possiblePiste à explorer
Une longue boucle de calculCPU et coût des opérations PythonAlgorithme, fonctions adaptées
Un fichier énorme lu en une foisRAMLecture progressive
Beaucoup de petits fichiersEntrées/sorties et gestion des fichiersRéduire les accès répétés
Attente d’une réponse webRéseau ou serveur distantConcurrence 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.

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

MotDéfinition
Instruction machineOpération que le CPU sait exécuter.
BytecodeReprésentation intermédiaire utilisée par CPython.
InterpréteurProgramme qui réalise les opérations du programme Python.
ProcessusProgramme en cours d’exécution avec ses ressources.
RéférenceLien 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.