Comprendre le noyau et l’ordre d’exécution d’un notebook Jupyter

Noyau Jupyter : un notebook envoie ses cellules au noyau Python, dont la mémoire peut être réinitialisée.

Pourquoi un notebook affiche-t-il encore un ancien résultat, ou échoue-t-il après un redémarrage ? Le noyau Jupyter conserve les variables des cellules déjà exécutées. Le résultat d’une cellule dépend donc du code que vous lancez et de l’état de cette mémoire au moment de l’exécution.

Un notebook réunit des cellules de code, du texte et des sorties dans un même document. Vous verrez comment Python, .venv et ipykernel permettent d’exécuter ses cellules, puis vous apprendrez à distinguer le fichier enregistré, la mémoire du noyau et les résultats affichés. Les exemples utilisent seulement les fonctions intégrées de Python pour observer les dépendances entre cellules et vérifier les calculs après un redémarrage.

Avant de commencer

Si votre premier notebook ne s’exécute pas encore, reprenez le guide pour installer Python et préparer Jupyter dans VS Code. Pour revoir les affectations, sum() ou les listes, consultez les bases de Python. La leçon sur la mutabilité et les copies complète ce sujet, mais le mécanisme étudié ici concerne aussi un simple nombre déjà calculé.

Python, .venv et ipykernel : comment fonctionne le noyau Jupyter ?

Lorsque VS Code vous demande de choisir un noyau, il vous propose souvent un nom d’environnement accompagné d’une version de Python. Pour comprendre ce choix, suivons ce qui se passe entre le document que vous ouvrez, les outils installés sur le disque et le programme qui exécute vos cellules.

Python : le langage et le programme qui l’exécute

Python désigne un langage de programmation : ses règles permettent d’écrire des instructions comme une affectation ou un calcul. Pour les exécuter, l’ordinateur utilise un programme appelé interpréteur Python. Le tutoriel officiel de Python présente son fonctionnement.

Un paquet est un ensemble de composants logiciels que vous pouvez installer pour ajouter des fonctionnalités. Un ordinateur peut héberger plusieurs interpréteurs Python et plusieurs ensembles de paquets. Il faut donc savoir lequel exécute réellement le notebook.

.venv : l’environnement Python du projet

Un environnement virtuel regroupe un interpréteur Python et les paquets installés pour un projet, isolés par défaut de ceux des autres environnements. Dans notre dossier projet-ia, cet environnement est rangé dans un sous-dossier nommé .venv. Vous pouvez le voir comme les outils préparés pour ce projet, disponibles sur le disque même lorsque le notebook est fermé.

Les noms se ressemblent, mais ils désignent deux choses précises : venv est le nom d’un module de Python qui permet de créer des environnements virtuels ; .venv est un nom de dossier choisi par convention. Le dossier pourrait porter un autre nom. La documentation de Python sur les environnements virtuels décrit cette organisation.

ipykernel : permettre à Python de communiquer avec Jupyter

ipykernel est un paquet Python qui fournit le noyau Python de référence pour Jupyter. Il prend en charge les échanges nécessaires avec l’interface : recevoir une demande d’exécution, faire exécuter le code et renvoyer les sorties ou les erreurs. Dans VS Code, l’extension Jupyter utilise ces échanges pour afficher les résultats sous vos cellules.

Pour démarrer un noyau avec l’interpréteur de votre .venv, ipykernel doit être disponible dans cet environnement. Sa présence dans un autre Python ne suffit pas. La documentation d’IPython sur les noyaux et les environnements explique ce lien.

Le noyau : un Python en cours d’exécution avec sa mémoire

Un processus est un programme en cours d’exécution. Dans le cas étudié ici, le noyau Jupyter est un processus Python lancé avec ipykernel, à partir de l’environnement sélectionné. L’environnement fournit les outils installés ; le noyau les utilise pendant votre session et garde les variables créées par vos cellules. La définition des noyaux dans Jupyter précise qu’ils fonctionnent indépendamment de leur interface.

Quand une cellule définit heures_etude, cette variable devient disponible dans la mémoire du noyau actif. Elle n’est pas rangée comme un nouveau fichier dans .venv. Redémarrer le noyau recrée une session de calcul ; le dossier de l’environnement et ses paquets restent sur le disque. Vous devez alors réexécuter les cellules qui préparent vos variables.

Le notebook dans VS Code envoie le code au noyau Python et reçoit les résultats. Le dossier .venv fournit Python et ipykernel pour démarrer ce noyau, qui conserve les variables en mémoire.
Sur le disque, .venv contient l’interpréteur et les paquets du projet. Pendant la session, Python et ipykernel font fonctionner le noyau : il reçoit le code de VS Code, conserve les variables et renvoie les résultats.

Du clic sur Exécuter au résultat affiché

  1. Dans le sélecteur de noyau du notebook, vous choisissez l’environnement Python du projet. VS Code peut alors lancer le Python correspondant avec ipykernel.
  2. Vous lancez une cellule. L’interface transmet son code au noyau actif.
  3. Python exécute les instructions avec les paquets de l’environnement et les variables déjà présentes dans cette session.
  4. Le noyau renvoie les sorties ou le message d’erreur. VS Code les affiche sous la cellule.
  5. Le noyau reste disponible pour les cellules suivantes : vous retrouvez les variables tant que cette session les conserve.

Choisir le bon noyau dans VS Code

Dans le notebook, ouvrez le sélecteur en haut à droite. Si l’environnement voulu n’apparaît pas dans les choix récents, utilisez Select Another Kernel…, puis Python Environments, et choisissez la .venv du projet. Le guide des noyaux de VS Code décrit ces choix.

Le sélecteur peut afficher un environnement même si ipykernel n’y est pas encore installé. Si VS Code signale ce manque, préparez cet environnement en reprenant le guide d’installation de Python et de Jupyter. L’extension Jupyter de VS Code et le paquet Python ipykernel ont des rôles complémentaires : l’une équipe l’éditeur, l’autre équipe le Python qui exécutera les cellules.

Le repère à conserver est le suivant : le notebook contient vos cellules, .venv fournit les outils du projet, ipykernel permet les échanges avec Jupyter, et le noyau exécute le code en gardant l’état de la session.

Noyau Jupyter : distinguer le fichier et la mémoire

Le notebook est le document enregistré sur le disque ; le noyau exécute son code dans une session de calcul. Le tableau suivant permet de distinguer les informations du fichier, l’interface qui les affiche et l’état du noyau.

ÉlémentRôleCe qu’il faut vérifier
Le fichier .ipynbConserve les cellules, leurs métadonnées et les sorties que vous enregistrez.Une sortie affichée peut provenir d’une exécution précédente.
L’éditeur de VS CodeAffiche le document et envoie vos demandes d’exécution.L’ordre des cellules dans la page n’impose pas l’ordre de vos clics.
Le noyau PythonExécute les instructions et conserve les objets de la session.Une variable peut exister en mémoire sans que sa définition soit encore visible dans le fichier.
Trois éléments à distinguer lorsque vous travaillez dans VS Code.
Le fichier .ipynb conserve les cellules et leurs sorties ; le noyau garde la liste 23, 19, 24 et le total 66 jusqu’à son redémarrage.
Le fichier conserve les cellules et les sorties enregistrées ; le noyau garde les variables de la session. Redémarrer le noyau réinitialise sa mémoire.

Deux notebooks peuvent utiliser la même .venv et donc les mêmes outils, tout en ayant des noyaux distincts. Dans ce cas, les variables créées dans l’un ne sont pas disponibles dans l’autre : chaque session possède sa propre mémoire.

Que se passe-t-il quand vous rouvrez un notebook ?

Supposons que vous enregistriez le notebook après avoir obtenu 66, puis que vous le rouvriez avec un nouveau noyau. Le nombre peut rester visible sous la cellule, car il fait partie des sorties enregistrées. Les noms heures_etude et total_heures doivent pourtant être définis à nouveau avant d’être utilisés.

Une sortie enregistrée montre le résultat d’un essai précédent. Pour reproduire le calcul, il faut relancer le code avec les ressources nécessaires. Lorsque vous partagez un notebook, conservez les sorties utiles à sa lecture et indiquez les fichiers et les paquets dont son exécution dépend.

Exécuter les cellules dans l’ordre de leurs dépendances

Une cellule dépend d’une autre lorsqu’elle utilise une valeur que cette autre cellule doit produire. La position de la définition dans le document ne suffit pas : vous devez exécuter la cellule qui crée cette valeur.

L’exemple reprend les trois premières valeurs de la colonne Hours_Studied du fichier StudentPerformanceFactors.xlsx : 23, 19 et 24. Chaque valeur correspond à un élève différent. Nous les saisissons directement dans la première cellule pour étudier l’ordre d’exécution sans avoir à lire le classeur dans cette leçon.

# Reprendre les trois valeurs vérifiées de Hours_Studied.
heures_etude = [23, 19, 24]
print("Heures :", heures_etude)
Heures : [23, 19, 24]
# Calculer le total à partir de la liste actuelle.
total_heures = sum(heures_etude)
# Afficher la valeur conservée dans le noyau.
print("Total :", total_heures)
Total : 66

La première cellule crée la liste heures_etude. La deuxième en calcule la somme et l’affecte à total_heures. La troisième affiche ce nombre : 23 + 19 + 24 = 66.

Le nombre entre crochets est un compteur d’exécution. Il indique le rang de la dernière exécution de la cellule dans la session où elle a été lancée. Il peut être conservé dans le fichier avec les sorties. Des compteurs désordonnés aident à repérer des exécutions hors de l’ordre de lecture ; des compteurs croissants ne garantissent pas, à eux seuls, que les résultats sont à jour.

Que se passe-t-il si vous lancez une cellule trop tôt ?

Appelons A la cellule qui crée la liste, B celle qui calcule le total et C celle qui l’affiche. B utilise la liste créée par A, puis C utilise le total calculé par B. Ces lettres repèrent les étapes du schéma ; elles sont distinctes des compteurs d’exécution.

A crée la liste 23, 19, 24 ; B calcule 66 ; C l’affiche. Dans un noyau neuf, C seule provoque NameError car total_heures est absent.
A crée la liste, B calcule le total et C l’affiche. Dans un noyau neuf, lancer C seule provoque une erreur : le nom total_heures n’a pas encore été défini.

Cas 1 : vous lancez C avant le calcul B

Redémarrez le noyau, puis lancez seulement C, la cellule d’affichage. Pour cet essai, laissez A et B sans les exécuter. Python doit alors lire total_heures, alors que ce nom n’existe pas encore dans la nouvelle session.

# Afficher la valeur conservée dans le noyau.
print("Total :", total_heures)
NameError: name 'total_heures' is not defined

Le message NameError indique ici que total_heures n’est pas défini. Le noyau exécute la cellule demandée ; il ne lance pas automatiquement B pour obtenir le total manquant.

Cas 2 : vous lancez B avant les données A

Redémarrez de nouveau le noyau, puis lancez seulement B. Le calcul demande cette fois la liste heures_etude, alors que A ne l’a pas encore créée.

# Calculer le total à partir de la liste actuelle.
total_heures = sum(heures_etude)
NameError: name 'heures_etude' is not defined

L’erreur concerne maintenant heures_etude. Sans cette liste, Python ne peut pas calculer la somme, et l’affectation à total_heures n’a pas lieu. Exécuter C ensuite provoquerait également une erreur, puisque le total reste absent.

Cas 3 : vous suivez A, puis B, puis C

Repartez d’un noyau neuf, puis lancez A, B et C. A crée [23, 19, 24] ; B calcule et mémorise 66 ; C affiche Total : 66. Chaque cellule trouve cette fois la valeur dont elle a besoin.

Un ancien noyau peut encore contenir les variables d’essais précédents. Une cellule lancée trop tôt pourrait alors afficher un nombre au lieu de provoquer une erreur. L’expérience suivante montre pourquoi cette absence d’erreur ne suffit pas à valider le calcul.

Pourquoi un ancien résultat peut rester affiché

L’instruction total_heures = sum(heures_etude) calcule la somme avec la liste disponible au moment où vous l’exécutez. Le nombre obtenu reste affecté à total_heures. Une modification ultérieure de la liste ne déclenche pas un nouveau calcul.

Gardons maintenant les deux premières observations, puis affichons le total déjà mémorisé, sans relancer sa formule.

# Garder uniquement les deux premières observations.
heures_etude = heures_etude[:2]
print("Heures actuelles :", heures_etude)
Heures actuelles : [23, 19]
# Cette instruction ne refait pas le calcul du total.
print("Total mémorisé :", total_heures)
Total mémorisé : 66

La liste vaut maintenant [23, 19], tandis que total_heures vaut toujours 66. Les deux noms existent, donc Python peut les afficher sans erreur. Le total correspond cependant à l’ancienne sélection de trois valeurs.

Relancez le calcul pour mettre le total en accord avec les données actuelles.

# Recalculer le total à partir de l’entrée modifiée.
total_heures = sum(heures_etude)
print("Total recalculé :", total_heures)
Total recalculé : 42
La liste réduite contient 23 et 19 ; l’ancien total 66 reste mémorisé, puis le recalcul donne 42.
Après réduction de la liste à 23 et 19, le total mémorisé reste 66. Réexécuter la somme le remplace par 42.

Le recalcul donne 42, soit 23 + 19. Le même décalage apparaît si vous remplacez la liste de la première cellule par [23, 19], puis relancez la préparation et l’affichage en oubliant la cellule de calcul.

Redémarrer, interrompre ou effacer les sorties

Ces commandes répondent à des besoins différents. Dans VS Code, elles se trouvent dans la barre d’outils du notebook ou son menu. Leurs libellés peuvent être affichés en anglais : Restart, Interrupt et Clear All Outputs.

ActionEffetLimite à connaître
Effacer les sortiesRetire les résultats visibles dans le document.Les variables du noyau restent disponibles.
InterrompreDemande l’arrêt du calcul en cours.N’annule pas les instructions déjà effectuées ; l’état peut être partiellement modifié.
Redémarrer le noyauRéinitialise la session de calcul, avec ses variables et ses imports.Ne supprime ni le fichier enregistré ni les paquets installés. D’anciennes sorties peuvent encore être visibles.
Exécuter toutLance les cellules dans l’ordre du document.Ne garantit pas, à lui seul, que le noyau a été réinitialisé avant l’exécution.
Effet des commandes sur le calcul et l’affichage.

Supprimer une cellule du document ne retire pas les objets qu’elle a déjà créés dans le noyau. Ces objets peuvent rester utilisables jusqu’au redémarrage et masquer une dépendance devenue invisible dans le fichier.

Vérifier le notebook dans un noyau neuf

Avant de partager un notebook, vérifiez qu’il fonctionne à partir des cellules et des ressources que vous transmettez. Un redémarrage suivi d’une exécution complète permet notamment de repérer une variable définie dans une cellule supprimée.

  1. Enregistrez le code actuel avec Ctrl + S.
  2. Vérifiez le noyau sélectionné en haut à droite et redémarrez-le.
  3. Utilisez Exécuter tout, en repartant de la première cellule.
  4. Vérifiez les sorties. Si une cellule échoue, repérez la première erreur et corrigez sa cause avant de recommencer la procédure.
  5. Appuyez à nouveau sur Ctrl + S pour enregistrer le notebook avec les sorties que vous venez de vérifier.
Cinq étapes : enregistrer le code, redémarrer le noyau, exécuter tout, vérifier les sorties, puis enregistrer le notebook avec ses sorties en appuyant sur Ctrl + S.
Après vérification des sorties, appuyez à nouveau sur Ctrl + S pour enregistrer le notebook avec les résultats affichés. Le fichier .ipynb conserve le code et ces sorties.

Étape 5 : enregistrer le notebook avec ses sorties

Une sortie est ce qu’une cellule affiche après son exécution : un texte, un nombre, un tableau ou un graphique. À cette dernière étape, vous sauvegardez à nouveau le fichier .ipynb pour qu’il conserve le code et les sorties que vous venez de vérifier.

Prenons la cellule qui affiche Total : 66. Après l’avoir exécutée, enregistrez le notebook, fermez le document, puis rouvrez-le : vous pouvez encore lire Total : 66 sous la cellule. Ce texte est une trace de l’exécution enregistrée dans le fichier, comme le précise la description du format notebook.

Conserver cet affichage ne sauvegarde pas la mémoire du noyau. Si vous démarrez un nouveau noyau, la variable total_heures doit être recréée en exécutant les cellules qui préparent les données et calculent le total. Le fichier permet de relire le résultat précédent ; relancer le code permet de le reproduire.

Exercice : retrouver une dépendance manquante

Redémarrez le noyau et prévoyez ce qui se passera si vous lancez seulement print("Total :", total_heures). Le nom total_heures sera-t-il défini dans le noyau ? Exécutez ensuite cette cellule sans lancer la préparation. Expliquez ce qui aurait changé si vous aviez seulement effacé les sorties.

Écrivez enfin une cellule autonome qui définit les trois valeurs initiales, calcule leur total et l’affiche. Elle doit donner le même résultat à chaque réexécution, sans dépendre d’une variable préparée ailleurs.

Voir la correction expliquée

Après le redémarrage, total_heures n’est pas défini : Python lève NameError. Voici la dernière ligne du message. La trace complète, appelée traceback, donne aussi des indications sur la cellule concernée.

print("Total :", total_heures)
NameError: name 'total_heures' is not defined

Effacer les sorties sans redémarrer ne supprime pas les variables déjà définies. Si total_heures existait dans le noyau actif, la cellule aurait affiché sa dernière valeur, sans refaire le calcul. Si ce nom n’avait jamais été défini, elle aurait quand même provoqué NameError.

Cette cellule réunit les données, le calcul et l’affichage. Son résultat ne dépend pas d’une variable préparée ailleurs.

# Réunir l’entrée et son calcul pour supprimer une dépendance cachée.
heures_etude = [23, 19, 24]
total_heures = sum(heures_etude)
print("Total vérifié :", total_heures)
Total vérifié : 66

Cette solution vérifie le petit calcul de l’exercice. Pour un notebook composé de plusieurs cellules, la même démarche s’étend à toutes leurs dépendances.

Que vérifier si le notebook ne se comporte pas comme prévu ?

SymptômeCause possiblePremier contrôle
NameErrorCellule de définition non exécutée, nom modifié ou faute de frappe.Relire le nom et exécuter la cellule qui le définit.
Résultat ancien sans erreurEntrée modifiée, mais calcul dépendant non relancé.Recalculer les résultats concernés, puis tester dans un noyau neuf.
Erreur d’importPaquet absent du Python sélectionné ou mauvais noyau.Vérifier sys.executable et reprendre le guide d’installation.
Calcul qui reste occupéCalcul long ou boucle qui ne se termine pas.Interrompre, puis examiner la cellule avant de la relancer.
Sortie encore visible après redémarrageRésultat conservé dans le document.Réexécuter la cellule ; sa sortie affichée ne prouve pas que ses variables existent.
Symptômes utiles pour orienter le diagnostic.

À retenir

L’environnement .venv fournit le Python et les paquets du projet ; ipykernel permet à ce Python de fonctionner comme noyau Jupyter. Ce noyau garde les variables de la session, tandis que le fichier notebook conserve les cellules et les sorties enregistrées. Il peut donc montrer un résultat alors qu’un nouveau noyau ne possède encore aucune de vos variables. Exécutez les cellules dans l’ordre de leurs dépendances, puis relancez les calculs concernés après une modification. Avant de partager le document, redémarrez le noyau, exécutez tout, contrôlez les sorties et enregistrez.

Références pour approfondir