A) Introduction
Les tableaux (ou listes) sont utilisés à diverses occasions au lycée en mathématiques, comme l’illustre par exemple le document « Algorithmique et programmation » publié sur Eduscol pour tenir compte des nouveautés de la rentrée 2017-2018. Page 5 de ce document, une phrase a particulièrement attiré mon attention et m’a plongé dans la perplexité :
Les listes ne font pas l’objet d’un enseignement spécifique en seconde, mais peuvent être utilisées comme objets simples et pratiques.
En tant qu’enseignant d’informatique en IUT, il me semble en effet loin d’être évident qu’on puisse facilement utiliser les listes sans enseignement spécifique ! Cela me conduira donc dans la première partie de l’article à montrer qu’il vaut mieux éviter certaines possibilités élégantes de Python, sous peine de noyer de nombreux lycéens, voire d’entraîner des confusions.
Dans la seconde partie de l’article, je m’intéresserai aux blocs proposés par Blockly pour gérer les listes : en effet on peut en obtenir automatiquement la traduction en Python, ce qui peut faciliter l’apprentissage de ce langage. Plus précisément, je m’intéresserai au logiciel SofusPy qui permet (en ligne ou localement) :
- de programmer par blocs (avec des blocs, adaptés à un contexte mathématique, qui complètent le « Blockly de base »)
- d’engendrer automatiquement le code Python à partir des blocs
- de compléter éventuellement le code engendré, puis de l’exécuter
B) Les listes en Python
Dans un cours de mathématiques, les listes sont avant tout utilisées pour manipuler des séries de nombres. En Python, il y a deux approches possibles :
- utiliser des variables indicées
- éviter d’utiliser des variables indicées, grâce à des primitives spécifiques aux listes
Pour illustrer mon propos, je vais commenter diverses versions d’un programme calculant la somme de 4 nombres stockés dans une liste :
t = [3, 6, 11, 18]
# version 1
print(t[0]+t[1]+t[2]+t[3])
# version 2
total = 0
for k in range(0,len(t)) :
total = total + t[k]
print(total)
# version 3
total = 0
for nombre in t :
total = total + nombre
print(total)
Télécharger
La première version illustre simplement que les éléments d’une liste sont accessibles par un numéro. On peut observer que la numérotation d’une liste débute à 0 en Python, contrairement à celle de Blockly qui débute à 1 : cela me conduit donc, dans la section C, à introduire de nouveau blocs afin d’uniformiser les deux numérotations dans SofusPy.
La seconde version, plus sophistiquée, introduit une boucle Pour permettant de calculer la somme d’une liste de taille quelconque.
La troisième version, spécifique aux listes, remplace la boucle Pour traditionnelle (faisant varier un indice entier) par une boucle Pour parcourant directement la liste, ce qui permet ensuite de ne plus utiliser de variables indicées.
Mais est-ce dans l’esprit d’un enseignement de mathématiques d’éviter les indices [1] ? Et, surtout, l’introduction d’une nouvelle boucle ne risque-t-elle pas de perturber de nombreux lycéens ? Bizarrement, cette question importante n’est pas abordée dans le document d’Eduscol, ni dans les documents fournis par de nombreux formateurs...
La troisième version n’a rien de nocif dans l’absolu, mais peut le devenir si on le fait « à la hussarde », ce qui me semble hélas être fréquent au lycée. Je veux bien admettre que les enseignants de mathématiques n’aient pas suffisamment de temps pour approfondir le codage, mais ça me semble alors contradictoire d’introduire un troisième type de boucle : les seules boucles exigibles dans le programme officiel sont en effet la boucle Tantque et la boucle Pour classique...
Le document d’Eduscol est hélas loin d’être le seul à suggérer de définir une liste en compréhension en seconde, comme dans cet exemple : t = [ k**2 + 2 for k in range(16) ].
Je devrais même dire mille fois hélas car il y a dans la notation une ressemblance frappante avec celle de la boucle Pour classique : chercherait-on délibérément à semer la confusion chez de nombreux élèves ? Il y a des jours où je me le demande…
Un membre du comité de rédaction de MathémaTICE m’a objecté que les listes en compréhension pouvaient être utiles dans un contexte mathématique. Si tel est le cas, il faudrait alors en préciser les raisons dans le programme officiel et en faire une priorité, alors que ce n’est qu’une notation Python parmi d’autres dans le document d’Eduscol. Et il faudrait bien sûr laisser suffisamment de temps aux élèves pour qu’ils assimilent cette notion sans la confondre avec une boucle Pour classique, ce qui n’est pas le cas dans le contexte actuel.
Avant de proposer une alternative aux listes en compréhension, je ferai un détour par les notations algorithmiques que j’utilise en première d’année d’IUT pour travailler avec des tableaux à une dimension :
Si on souhaite conserver la notation indicée en Python, il faut recourir à un artifice pour indiquer que le tableau de l’algorithme (implanté en Python avec une liste) comporte 16 valeurs, par exemple en introduisant une liste de 16 zéros :
t = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] # ou t = [0]*16
for k in range(0,16) :
t[k] = k**2 + 2
print(t)
Télécharger
L’artifice relevant plus du bidouillage que de la pédagogie, je renoncerai donc ici à la notation indicée pour proposer cette alternative à la liste en compréhension :
t = []
for k in range(0,16) :
t.append(k**2+2)
print(t)
Télécharger
La liste est initialement vide, puis on la complète au fur et à mesure en ajoutant les valeurs en fin de liste (méthode append). Il est à noter que cette solution est souvent présente dans les documents proposés aux enseignants de mathématiques : ouf, il arrive parfois que nous trouvions un terrain d’entente ! Plus sérieusement, le vrai problème est que les documents proposés aux enseignants de mathématiques dressent souvent un inventaire à la Prévert : mon souci est donc de le réduire, le mieux pouvant être l’ennemi du bien.
C) Les listes en programmation visuelle avec SofusPy
Page 7 du document Eduscol, il y a un paragraphe intitulé « De Scratch à Python » dont voici un petit extrait :
En classe de seconde, le passage de Scratch à Python peut être immédiat ou progressif, suivant les choix pédagogiques de l’enseignant. Les deux langages comportent, au-delà des différences évidentes de forme, des similitudes qui facilitent la transition.
Voici un exemple : un tracé géométrique en Scratch, et son analogue en Python.
À ma connaissance, il n’y a hélas aucun outil permettant de passer automatiquement d’un programme visuel Scratch à un programme Python. C’est pourquoi, en liaison avec Alain Busser qui a développé le logiciel Sofus (extension de Blockly adaptée à un cadre mathématique), j’ai créé un logiciel nommé SofusPy qui le complète en assurant une passerelle entre programmation visuelle et Python.
Cela nous a conduit à publier sur le site de l’IREM de la Réunion un article intitulé « SofusPy, une passerelle entre programmation visuelle et Python ». Les listes n’étant pas évoquées dans cet article, je vais donc le compléter.
Cela m’amènera à évoquer les blocs existants dans le Blockly de base, à en montrer certaines limites et donc à proposer de nouveaux blocs. Bien évidemment, le tout sera illustré avec quelques exemples mathématiques et leur traduction automatisée en Python.
Il existe deux blocs permettant d’initialiser une liste :
Par défaut, le bloc « créer une liste avec » est configuré pour créer une liste de taille 3. Quelques manipulations permettent de modifier cette taille, mais cela sera fastidieux avec une liste de taille 16 par exemple.
Heureusement, c’est moins gênant qu’il n’y paraît puisque l’objectif final est d’apprendre à programmer en Python : on peut donc se contenter d’attribuer 3 valeurs par défaut, puis récupérer la traduction en Python du programme visuel, puis d’ajouter les autres valeurs directement dans la traduction Python du bloc.
Blockly propose un bloc « obtenir » permettant de récupérer une valeur en donnant sa position, bloc qui par ailleurs propose diverses autres options :
La notation, lourde, rendrait problématique l’utilisation du bloc « obtenir » dans une expression plus complexe, par exemple pour afficher t[k]*t[k]. De plus la traduction du bloc en Python sera ici t[k-1] (en fait t[int(k-1)]) car il y a un décalage entre la numérotation Blockly (débutant à 1) et la numérotation Python (débutant à 0).
C’est pourquoi, même si j’ai laissé dans SofusPy le bloc « obtenir », j’ai décidé de lui adjoindre un nouveau bloc plus concis et adapté à la numérotation des listes en Python :
Pour terminer, je signale que Blockly propose une boucle permettant de parcourir directement une liste sans indices, boucle ne figurant pas au programme officiel, mais que j’ai quand même intégrée dans SofusPy pour ne pas frustrer les experts en Python :
Voici le code Python obtenu en cliquant sur le bouton « Editeur » de SofusPy :
t = [2, 3, 10]
for valeur in t:
print(valeur * valeur)
Blockly propose un bloc « mettre » permettant de mettre une valeur dans une liste en donnant sa position. A l’instar du bloc « obtenir », il ne me satisfait guère, ce qui m’a donc conduit à introduire deux nouveaux blocs : un pour ajouter un élément en fin de liste (voir ci-dessous) et un pour mettre une valeur en donnant sa position.
Voyons maintenant ce qui se passe si on remplace le bloc « ajouter en fin de liste » par le bloc « fixer ... [...] à ... » :
Si on exécute le programme Blockly, on obtient le résultat attendu. Par contre, si on essaie d’exécuter le code Python engendré par SofusPy, il y a une erreur :
Cette erreur provient de ce que t n’a pas été initialisé correctement, par exemple avec une liste de 16 zéros, artifice relevant plus du bidouillage que de la pédagogie comme je l’avais indiqué dans la section B.
Et si le programme Blockly marche, cela tient à une particularité de Javascript, langage dans lequel le programme visuel est traduit pour pouvoir être interprété : il n’est pas nécessaire d’allouer au départ une taille (ici 16) avant de placer les 16 valeurs.
Au passage, j’en profite pour signaler que, contrairement à une idée reçue, le choix d’un langage de programmation peut grandement influencer la façon d’enseigner (au delà des différences de syntaxe) :
- en Javascript (et donc en AlgoBox puisqu’un programme AlgoBox est interprété en Javascript), on n’a pas à se soucier de la taille d’une liste pour y placer une valeur à une position donnée
- en Python, on ne peut pas procéder ainsi, ce qui conduit à :
- soit, comme dans de nombreux langages, à fixer la taille de la liste au départ afin de pouvoir utiliser des notations du style « t[position]=valeur »
- soit à programmer avec des méthodes spécifiques aux listes (ajouter une valeur à la fin, supprimer un élément de la liste), en introduisant de nouvelles boucles (parcours d’une liste)...
Pédagogiquement, ce choix de ne jamais rien imposer et de ne jamais fixer de ligne directrice claire est une aberration. Cet « art d’enseigner salement la programmation » [2] se pratique depuis des années au lycée et aboutit à des questions de bac ridiculement simplistes.
En plus, les impératifs mathématiques conduisent à introduire prématurément les listes (ou tableaux) en codage, d’autant qu’on complique souvent la tâche des élèves en combinant listes et sous-programmes : pourquoi fait-on mine d’ignorer au lycée [3] que cette combinaison met en difficulté de nombreux étudiants d’IUT par exemple ?
Blockly propose un bloc « somme d’une liste » qui, grâce à une liste déroulante, permet en fait de faire diverses statistiques :
La traduction en Python est facile à comprendre lorsqu’il existe déjà une fonction prédéfinie calculant la statistique demandée : sum (somme), min (minimum) et max (maximum). Lorsqu’il n’existe pas de fonction prédéfinie en Python, par exemple pour calculer une moyenne, une fonction est alors définie et intégrée dans la traduction :
def math_mean(myList):
localList = [e for e in myList if type(e) in (int, float, long)]
if not localList: return
return float(sum(localList)) / len(localList)
t = [2,3,10]
print(math_mean(t))
Télécharger
Même si le code de ces fonctions n’est pas toujours très compréhensible, peu importe au fond : l’important est que les élèves sachent ensuite utiliser ces fonctions. Et puis, à titre d’exercice, les enseignants peuvent ici très bien demander aux élèves de proposer un code plus clair pour définir la fonction math_mean...
Pages 14 et 15 du document Eduscol, un exemple de simulations avec un dé truqué (une face 1, trois faces 2 et deux faces 4) est présenté dans un paragraphe intitulé « stabilisation des fréquences ». Il aboutit à une illustration graphique avec la librairie pyplot, ce que ne peut faire SofusPy car son interpréteur Python ne dispose pas de cette librairie graphique. Mais il est possible de réaliser avec SofusPy tout le travail en amont, ce qui conduit ici à créer 3 listes :
- la liste des lancers
- la liste des moyennes partielles
- la liste des entiers de 1 au nombre d’expériences
Les deux dernières listes (Y et X) correspondent aux ordonnées et aux abscisses des points sur le graphique. A titre indicatif, voici le code (légèrement modifié) donné par Eduscol :
import matplotlib.pyplot as plt
plt.plot(X, Y,'b.') # points en bleu
plt.grid()
plt.show()
Télécharger
En amont, on peut créer les 3 listes avec ce programme visuel, puis en obtenir la traduction en Python :
Après la génération d’un entier aléatoire entre 1 et 6, certaines faces sont renumérotées. Il serait possible avec SofusPy d’introduire une fonction comme dans Eduscol, mais j’ai choisi de m’en passer car j’estime qu’elle rendrait le programme plus abstrait, ce que je cherche à éviter.
Les différentes moyennes sont calculées à l’aide de la fonction moyenne, ce qui n’est pas très efficace en temps d’exécution (les mêmes sommes étant effectuées plusieurs fois), mais ce qui simplifie la conception de l’algorithme.
Voici le code Python obtenu :
import random
def math_mean(myList):
localList = [e for e in myList if type(e) in (int, float, long)]
if not localList: return
return float(sum(localList)) / len(localList)
n = 100
X = []
Y = []
lancers = []
for k in range(1,n+1) :
de = random.randint(1, 6)
if de >= 5:
de = 4
elif de >= 3:
de = 2
lancers.append(de)
Y.append(math_mean(lancers))
X.append(k)
print(lancers)
print(Y)
print(X)
Télécharger
Pour en terminer avec cet exemple, je tiens à signaler que je l’ai traité uniquement parce qu’il figure dans le document d’Eduscol : je montre que SofusPy peut le rendre moins indigeste, tout en espérant qu’il ne soit pas traité du tout ! J’ajouterai que j’avais été critique dans le N°47 de MathémaTICE (voir lien) sur l’écriture d’algorithmes de simulations pour enseigner le codage, allant même jusqu’à écrire des sketches satiriques : je préfère de simples simulations avec un tableur, ou un code directement fourni aux élèves pour être testé sans qu’on leur impose d’en comprendre le sens.
D) Conclusion
Avec Alain Busser, nous avons publié sur le site de l’IREM de la Réunion un article intitulé « SofusPy, une passerelle entre programmation visuelle et Python ». Les listes n’étant pas évoquées dans cet article, je l’ai donc complété, ce qui m’a conduit à définir de nouveaux blocs pour faciliter l’écriture de programmes mathématiques Blockly avec des listes et, par conséquent, l’écriture de programmes mathématiques Python avec des listes.
Mais un logiciel peut-il suffisamment faciliter la tâche des élèves dans le contexte actuel où on veut aller plus vite que la musique au lycée, sans prendre le temps de consolider certains acquis algorithmiques avant d’utiliser des listes dans des programmes mathématiques ?