Chapitre 1 La programmation

Qu'est-ce qu'un programme?

De manière générale, un programme est une suite d'actions à entreprendre visant à atteindre un but. On peut par exemple dire d'une recette de cuisine que c'est un programme pour réaliser un plat (cf figure). On parle également de programme pour un lave-linge où, suivant le type de linge, la suite d'actions (rotations du tambour) est différente.

Cuire un œuf

Un programme est donc constitué d'une suite d'instructions à exécuter dans un certain ordre.

Dans le domaine de l'informatique, un programme est une suite d'instructions visant à la résolution d'un problème. La résolution d'une équation du deuxième degré que vous avez apprise en secondaire ressemble déjà beaucoup à un programme informatique (cf figure).

Second degré

Code et langage de programmation

Les figures et sont des représentations graphiques de programmes. On les appelle organigrammes ou encore diagrammes d'activité. Un vrai programme se fait dans un langage de programmation. Un programme écrit dans un langage de programmation se présente donc comme du texte. Ce texte est appelé le code source du programme.

Une façon d'écrire en texte le programme de résolution d'une équation du second degré pourrait être la suivante :

b*b-4*a*c → D
si D < 0 alors:
    affiche "Pas de solution réelle"
sinon:
    si D = 0 alors:
        affiche "La racine double est" -b/(2*a)
    sinon:
        affiche "La 1re racine est" (-b-sqrt(D))/(2*a)
        affiche "La 2e racine est" (-b+sqrt(D))/(2*a)
Pseudo code, second degré

Le texte ci-dessus est souvent appelé "pseudo-code" car il a une structure très proche d'un vrai code de programme mais il n'est écrit dans aucun langage de programmation particulier.

Pour écrire un vrai programme, il faut choisir un langage de programmation et respecter sa syntaxe. Le langage que nous allons utiliser dans ce cours est le Python. Voici la version Python du précédent pseudo-code:

D = b*b-4*a*c
if D < 0:
    print("Pas de solution réelle")
else:
    if D == 0:
        print("La racine double est", -b/(2*a))
    else:
        print("La 1re racine est", (-b-sqrt(D))/(2*a))
        print("La 2e racine est", (-b+sqrt(D))/(2*a))
Python, second degré

Dans un programme, chaque ligne du code est une instruction. Les instructions sont exécutées dans l'ordre où elles apparaissent dans le code du programme.

"Les instructions sont exécutées...", mais comment sont-elles exécutées et par quoi ? Où se trouve ce fameux code du programme ?

Pour bien comprendre tout cela, nous allons devoir nous intéresser au fonctionnement d'un ordinateur.

Qu'est-ce qu'un ordinateur ?

Nous allons ici essayer de comprendre comment un ordinateur fait pour exécuter du code. Pour pouvoir programmer, nous n'avons pas besoin de tout connaître dans les détails. Mais comprendre les bases du fonctionnement d'un ordinateur nous aidera pour le programmer et pour l'utiliser correctement.

Un ordinateur est, avant tout, un système composé de plusieurs éléments: processeur, mémoire, stockage, périphériques, ...

CPU, RAM, et stockage

Le processeur

Le processeur (CPU: Central Processing Unit) exécute les instructions d'un programme une par une. Ces instructions proviennent de la mémoire. Après avoir exécuté une instruction, il passe automatiquement à celle qui suit dans la mémoire. Certaines instructions peuvent cependant le faire sauter à un tout autre endroit de la mémoire pour continuer l'exécution.

Les instructions manipulent généralement des données. Par exemple, l'instruction permettant d'additionner va nécessiter d'aller chercher les valeurs à additionner. Les données sont elles aussi en mémoire. Et les résultats des calculs sont eux aussi sauvés en mémoire une fois qu'ils ont été calculés.

En bref, le processeur est donc grosso-modo capable de deux choses: calculer et sauver/lire des valeurs en mémoire.

Encore une petite remarque à propos du processeur : il ne comprend que le langage pour lequel il a été conçu. On appelle ce langage le jeu d'instructions du processeur ou encore langage machine. Il existe des jeux d'instructions différents pour chaque architecture de processeur (x86, ARM, ...).

La mémoire

La mémoire (RAM: Random Access Memory) contient les instructions du programme et les données qu'il manipule. Sa taille ne dépasse généralement pas quelques giga-octets (Go).

On peut se représenter la mémoire comme une longue liste de cases ayant chacune un numéro. Lorsque le processeur veut obtenir une instruction ou une donnée en mémoire, il doit mentionner le numéro de la case qu'il souhaite consulter.

Pour garder ses données, la mémoire a besoin d'être alimentée ce qui veut dire que le contenu de la mémoire est perdu si on lui coupe le courant. On dit que la mémoire est volatile.

Quand nous écrirons des programmes, nous manipulerons beaucoup la mémoire par l'intermédiaire des variables.

Le stockage

Puisque la mémoire est volatile et limitée en taille, comment stocke-t-on de grandes quantités de données et comment fait-on quand on éteint l'ordinateur ? On utilise un stockage de masse.

Il en existe plusieurs sortes :

Le stockage de masse contient des fichiers et des répertoires. Un répertoire peut contenir plusieurs fichiers et plusieurs autres répertoires. Le contenu du stockage de masse est donc organisé en une hiérarchie de répertoires et chaque élément dans cette hiérarchie peut être localisé par son chemin d'accès. Le chemin d'accès est constitué de la suite de répertoires à ouvrir pour atteindre l'élément.

Exemple:

Lorsqu'un programme doit être exécuté, ses instructions se trouvent initialement dans un fichier dans le stockage de masse. Les fichiers contenant des instructions pour le processeur sont appelés des fichiers exécutables (sous Windows, on les reconnaît car leurs noms finissent par ".exe"). Pour exécuter un de ces fichiers, le système d'exploitation (OS: Operating System) va d'abord le copier dans la mémoire. Le processeur pourra alors commencer à en exécuter les instructions.

De même, pour qu'un programme en cours d'exécution puisse accéder au contenu d'un fichier, il devra d'abord le charger en mémoire.

Les opérations d'écriture et de lecture de fichiers sont beaucoup plus lentes que les accès à des données en RAM. Les stockages de masse n'ont pas besoin d'être alimentés pour conserver les données (ils sont persistants) et peuvent contenir jusqu'à plusieurs tera-octets (To : ~1000 Go).

Comme nous l'avons vu, un programme se présente en pratique comme un simple texte et nous sauverons ce texte dans un fichier.

Langage de programmation

Les fichiers contenant des programmes contiennent les instructions du programme dans le langage propre au processeur. Par exemple, le jeu d'instructions des processeurs x86 (i3, i5, i7, amd ryzen, ...) est complètement différent de celui des processeurs ARM (Apple Silicon, Snapdragon, ...).

Ces jeux d'instructions sont faits pour s'exécuter aussi efficacement que possible par le processeur. Mais ils sont particulièrement difficiles à lire et à écrire par un être humain.

Pour créer un programme, on passe donc généralement par un langage de programmation.

Un langage de programmation est fait pour être écrit et lu par un être humain. Le code source d'un programme est un simple fichier texte. Le code source doit ensuite être traduit en langage machine pour pouvoir être exécuté par le processeur. En fonction du moment où cette traduction a lieu, on distingue deux grandes familles de langage de programmation: les langages compilés et les langages interprétés.

Dans un langage compilé, la traduction se fait par un programme appelé compilateur. Le compilateur génère un fichier exécutable à partir du fichier de code source. Le contenu de ce fichier exécutable peut ensuite être exécuté directement par le processeur et le compilateur n'est plus nécessaire.

Dans un langage interprété, la traduction se fait par un programme appelé interpréteur. L'interpréteur ne produit pas de fichier exécutable. Il exécute directement chaque instruction qu'il rencontre dans le code source. On a donc le processeur qui exécute l'interpréteur et l'interpréteur qui exécute notre code source. Dans ce cas, l'interpréteur est nécessaire pour chaque exécution du code source.

Le langage que nous allons utiliser dans ce cours est un langage interprété nommé Python. Pour exécuter un programme Python, il est nécessaire d'installer l'interpréteur Python.

Exécuter mon premier programme Python

La première chose à faire est d'installer l'interpréteur Python. Pour cela, il faut commencer par le télécharger sur https://python.org. Attention : sous Windows, cochez la case "Add Python to PATH" durant l'installation !

Site de Python

Cela fait, nous avons l'interpréteur Python installé. Cet interpréteur va nous permettre d'exécuter nos programmes. Il ne va par contre pas nous aider à écrire notre programme.

Comme le code d'un programme est un simple texte, la seule chose dont on a besoin pour écrire un programme est un éditeur de texte (Bloc-note sous Windows, TextEdit sous MacOS, ...). Il est cependant plus pratique d'utiliser un éditeur spécialisé pour écrire le code. Ces éditeurs facilitent fortement l'écriture et la lisibilité du code (Zed, Visual Studio Code, Notepad++, Sublime Text, ...). Dans ce cours, nous utiliserons Zed comme éditeur.

Pour installer Zed, il faut le télécharger sur le site https://zed.dev/.

Site de Zed

Une fois Zed installé, nous pouvons créer un nouveau fichier avec le contenu suivant :

print('Hello World !')
Le fichier hello.py

Une fois le code écrit, enregistrez le fichier sous le nom hello.py. Faites attention au répertoire dans lequel vous sauvez votre fichier. Nous aurons en effet besoin de connaître le chemin d'accès de notre fichier pour l'exécuter avec l'interpréteur Python. Le fait de faire terminer le nom du fichier par l'extension .py est une convention qui aide à identifier le type de contenu d'un fichier sans avoir nécessairement besoin de l'ouvrir.

Maintenant que notre fichier est créé, nous allons pouvoir l'exécuter avec l'interpréteur Python. Le problème, c'est que l'interpréteur n'a pas d'interface graphique !

Il est probable que la plupart des programmes que vous avez eu l'habitude d'utiliser par le passé soient des programmes ayant une interface graphique. On interagit généralement avec ce genre de programme en cliquant sur l'interface graphique avec la souris de l'ordinateur. L'interpréteur Python, lui, n'a pas d'interface graphique et les programmes que nous allons créer dans un premier temps n'en auront pas non plus. Il va donc falloir que nous apprenions à utiliser le terminal pour interagir avec des programmes en ligne de commande.

Nous nous pencherons sur l'utilisation du terminal dans la section suivante. Pour le moment, nous allons essayer de lancer rapidement notre premier programme. Lancez un terminal (Application "Powershell" sous Windows et "Terminal" sous MacOS) et tapez la commande qui suit pour démarrer l'interpréteur avec notre fichier hello.py. Le chemin d'accès mentionné est un exemple. Vous devez utiliser le chemin d'accès du fichier que vous avez créé précédemment. Attention: le premier caractère > représente l'invite de commande. Vous ne devez pas le taper. Sous MacOS, vous devrez sans doute utiliser la commande python3 à la place de python. Prenez garde aussi au format du chemin d'accès; il est différent entre Windows et MacOS.

Sous Windows :

> python C:\Users\lur\Documents\Programmation\hello.py

Sous MacOS :

> python3 /Users/lur/Documents/Programmation/hello.py

Validez avec la touche Enter. Vous devriez maintenant voir apparaître le message "Hello World !" dans le terminal en dessous de la commande que vous avez tapée.

Félicitations vous venez d'exécuter votre premier programme !

Il faut bien avouer que taper le chemin complet du fichier est un petit peu fastidieux. Nous allons donc essayer d'en apprendre un peu plus sur le terminal pour pouvoir l'utiliser plus efficacement.

Terminal

Une bonne partie de l'utilisation d'un ordinateur passe par la création, l'édition et la gestion de fichiers dans l'arborescence de dossiers du stockage de masse. Bien que de nos jours la plupart des gens fassent ces opérations en utilisant une interface graphique, il est aussi possible de les réaliser en ligne de commande dans un terminal.

Sous Windows, il y a plusieurs programmes permettant d'utiliser les lignes de commande :

Sous MacOS, le programme s'appelle simplement "Terminal".

Les développeurs et les ingénieurs sont régulièrement amenés à utiliser le terminal. Il est donc important d'apprendre les bases de son utilisation.

La première notion à intégrer est la notion de répertoire courant. Lorsqu'on utilise le terminal, il y a toujours un dossier de l'arborescence qui est considéré comme notre position actuelle. On peut afficher le chemin de ce dossier avec la commande pwd pour print working directory. Beaucoup de commandes agissent directement sur le répertoire courant.

> pwd
C:\Users\lur

La commande ls permet de lister le contenu du répertoire courant.

> ls
Desktop Documents

La commande cd (change directory) permet de changer le répertoire courant.

> cd Documents
> pwd
C:\Users\lur\Documents

On indique le nouveau répertoire courant par son chemin relatif ou absolu :

Remarques :

La touche Tab

Du coup, pour pouvoir démarrer notre programme Python plus facilement, il suffit de mettre le répertoire contenant le fichier .py comme répertoire courant :

> pwd
C:\Users\lur
> cd Documents\Programmation
> pwd
C:\Users\lur\Documents\Programmation
> python hello.py

De plus, si on souhaite relancer le programme, il suffit d'appuyer sur ↑ pour récupérer la dernière commande et puis de valider avec Enter.

Sachez aussi qu'il est possible d'ouvrir un terminal dans l'interface de Zed. Si vous ouvrez votre répertoire de travail dans Zed (File → Open...), tous les terminaux que vous ouvrirez commenceront automatiquement avec votre répertoire de travail comme répertoire courant!

La variable d'environnement PATH

Nous avons vu plus haut que l'interpréteur Python était un programme dont les instructions en langage machine se trouvent dans un fichier exécutable nommé python.exe (sous Windows). Mais comment fait le terminal pour savoir où se trouve ce fichier exécutable lorsqu'on tape la commande python?

En réalité, le fichier python.exe peut se trouver à plusieurs endroits. Si vous avez fait une installation simple sous Windows, il se trouve normalement dans :

C:\Users\lur\AppData\Local\Programs\Python\Python3XX\python.exe

Et on peut démarrer un programme dans le terminal en utilisant ce chemin complet :

> C:\Users\lur\AppData\Local\Programs\Python\Python311\python.exe C:\Users\lur\Documents\Programmation\hello.py

Mais ce n'est pas très pratique.

Pour éviter d'avoir à taper les chemins entiers des fichiers exécutables, la variable PATH contient une liste de dossiers dans laquelle le système d'exploitation va pouvoir chercher.

Lors de l'installation de l'interpréteur Python, vous avez normalement coché la case "Add Python to PATH". Cela a fait en sorte que le programme d'installation ajoute le répertoire C:\...\Python3XX à la liste de dossiers de la variable PATH. Et maintenant, à chaque fois que l'on utilise la commande python, le système d'exploitation cherche un programme nommé python.exe dans les dossiers listés dans PATH et il le trouve dans C:\...\Python3XX.

Pour finir, voici un schéma qui récapitule les opérations qui ont lieu quand on lance une commande (python) dans le terminal :

Exécution de la commande python par le terminal

Erreurs et débuggage

Nous avions vu, plus haut, un exemple de programme pour résoudre les équations du second degré :

D = b*b-4*a*c
if D < 0:
    print("Pas de solution réelle")
else:
    if D == 0:
        print("La racine double est", -b/(2*a))
    else:
        print("La 1re racine est", (-b-sqrt(D))/(2*a))
        print("La 2e racine est", (-b+sqrt(D))/(2*a))
Python, second degré

Il est maintenant temps d'essayer de l'exécuter. Sauvez ce programme dans un nouveau fichier, 2nd_order.py et essayez de le lancer :

> python 2nd_order.py
Traceback (most recent call last):
  File "C:\Users\lur\Programmation\2nd_order.py", line 1, in <module>
    D = b*b-4*a*c
        ^
NameError: name 'b' is not defined

Il semblerait que quelque chose se soit mal passé. Ce que nous avons là est un message d'erreur. C'est un des grands avantages de la programmation. Lorsqu'on fait une erreur, il y a généralement un message d'erreur pour nous aider à la corriger. Il est important d'apprendre à lire ces messages car toute l'information dont on a besoin pour corriger l'erreur se trouve généralement dans le message.

Ici le message d'erreur nous indique que le problème se trouve dans le fichier 2nd_order.py à la ligne 1. Le caractère ^ indique à quel endroit de la ligne se trouve l'erreur. Et la dernière ligne du message est une description de l'erreur. Ici, on nous dit que le nom b n'est pas défini.

En effet, nous n'avons, dans ce programme, pas défini les valeurs de a, b et c. Python ne peut donc pas effectuer le calcul b*b-4*a*c. Le message d'erreur nous parle de b car c'est la première variable non définie qu'il rencontre.

Ajoutons des définitions pour ces 3 variables :

a = 1
b = 0
c = -4
D = b*b-4*a*c
if D < 0:
    print("Pas de solution réelle")
else:
    if D == 0:
        print("La racine double est", -b/(2*a))
    else:
        print("La 1re racine est", (-b-sqrt(D))/(2*a))
        print("La 2e racine est", (-b+sqrt(D))/(2*a))
définitions des valeurs a, b et c

Relançons le programme :

> python 2nd_order.py
Traceback (most recent call last):
  File "C:\Users\lur\Programmation\2nd_order.py", line 11, in <module>
    print("La 1re racine est", (-b-sqrt(D))/(2*a))
                                   ^^^^
NameError: name 'sqrt' is not defined

Encore une erreur, la fonction sqrt() qui permet de calculer les racines carrées n'est pas chargée par défaut en Python. Comme nous ne l'avons pas chargée, le nom sqrt n'est pas défini. Ajoutons l'importation de la fonction sqrt :

from math import sqrt

a = 1
b = 0
c = -4
D = b*b-4*a*c
if D < 0:
    print("Pas de solution réelle")
else:
    if D == 0:
        print("La racine double est", -b/(2*a))
    else:
        print("La 1re racine est", (-b-sqrt(D))/(2*a))
        print("La 2e racine est", (-b+sqrt(D))/(2*a))
Importation de la fonction sqrt

Relançons le programme :

> python 2nd_order.py
La 1re racine est -2.0
La 2e racine est 2.0

Et voilà ! Ça marche.

Nous avons eu ici un exemple classique de rédaction de programme. On écrit du code, on teste, on lit les messages d'erreur, on corrige et on recommence.