Pour collègues geeks
Une utilisation en classe
Cet article peut être librement diffusé et son contenu réutilisé pour une utilisation non commerciale (contacter l’auteur pour une utilisation commerciale) suivant la licence CC-by-nc-sa (version originale). Il a été écrit pendant l’été 2018.
Le langage de programmation Python est maintenant suggéré en classe de seconde. Après quelques tentatives directes infructueuses, l’utilisation du µPython dans l’émulateur de Numworks m’a paru un meilleur choix.
Pourquoi la calculette Numworks ? Parce que j’avais l’émulateur sous la main, que je pouvais le bidouiller et le recompiler sans demander quoi que ce soit à mon administrateur contrairement à un environnement de développement ou à un émulateur concurrent. Je ne sais pas si j’aurais tenté si Python avait été installé, ça m’aurait demandé moins de travail.
Attention, à partir de la version 16.3.0 du code source de la calculatrice, on ne peut plus le diffuser librement (il n’est plus protégé par une licence libre).
L’an dernier, j’ai déjà utilisé Python en demi-groupe en classe mais le faible niveau des élèves en programmation a rendu les heures pénibles.
Ainsi, je proposais de se connecter à un site comme ideone pour y exécuter des bouts de script en Python (calculs, quelques tests et boucles simples) mais les élèves ne voyaient pas la finalité de ce b.a.-ba et perdaient beaucoup de temps avec les fautes de frappe et le respect de la syntaxe.
Finalement, je me suis rabattu les deux premiers trimestres de cette année sur Algobox en construisant cinq heures sur les entrées et sorties, les tests, les boucles pour, les boucles tant que et enfin les fonctions (présentes dans la version 1.0.2). Les élèves devaient recopier un script presque complet dans leur fenêtre d’Algobox mais leur manque d’aisance dans l’utilisation d’Algobox leur a pris beaucoup de temps avant de pouvoir commencer à comprendre ce qu’ils faisaient, même la cinquième et dernière heure.
Proposer des scripts incomplets à ouvrir et modifier ? Je n’y avais pas pensé et il me semblait, puisqu’il n’y a pas d’erreur de syntaxe dans Algobox, que ce serait plus facile.
Depuis 2017, Numworks vend une calculatrice qui contient une version simplifiée de Python (µPython 1.9.4 donc sans gestion des accents). Ses spécifications techniques sont publiques et son code source peut se compiler dans une version en JavaScript (comme sur leur site). L’énorme avantage est qu’il n’y a rien à installer, juste trois fichiers à copier quelque part dans un répertoire accessible aux élèves et un navigateur comme Chrome ou Firefox. Bonus pour moi, je peux compiler depuis Linux, ça fonctionnera dans Windows (ou Mac ou tout ce qu’on veut).
Avantage supplémentaire, il n’a pas besoin d’un environnement de développement qui nécessite une installation par l’administrateur.
J’ai donc compilé moi-même l’émulateur de la calculette en JavaScript puisqu’on ne peut pas, pour le moment, sauvegarder l’état de l’émulateur. J’y ai alors inséré les bouts de scripts dont j’avais besoin pour deux heures en seconde et deux heures en 1STI. Voir le bloc ci-dessous pour plus d’informations sur la compilation.
La compilation est expliquée sur leur site. Pour compiler en JS, on installe en plus emscripten et on tape
On insère le code source dans
Vous pouvez demander de l’aide sur le forum officiel où l’équipe de Numworks est active et disponible.
Les élèves pouvaient télécharger l’archive contenant l’émulateur à partir du logiciel de cahier de textes.
Puisque j’ai abordé les cinq parties du programme d’algorithmique (mais sans Python) pendant les deux premiers trimestres, j’ai tenté Python avec une autre approche. Lors de la première des deux heures (je n’ai pas eu le temps de faire plus), ils avaient à leur disposition l’émulateur de la calculette (fichiers joints python1.pdf pour le document et python1.zip pour l’émulateur).
L’application Python contenait les trois scripts corrects suivants :
Un script qui affiche un petit sapin de taille variable.
def sapin(n): for i in range(n): print(" "*(n-i)+"#"*(2*i+1)) print(" "*n+"#")
Un autre qui détermine la nature d’un triangle si on lui donne les noms et coordonnées de ses trois sommets.
def triangles(A,B,C): def distance2(A,B): pA,xA,yA=A pB,xB,yB=B return (xB-xA)**2+(yB-yA)**2 pA,xA,yA=A pB,xB,yB=B pC,xC,yC=C dAB2=distance2(A,B) dBC2=distance2(B,C) dCA2=distance2(C,A) nom=pA+pB+pC if dAB2==dBC2==dCA2: print(nom+" est equilateral.") elif dAB2==dBC2: print(nom+" est isocele en "+pB+".") elif dBC2==dCA2: print(nom+" est isocele en "+pC+".") elif dCA2==dAB2: print(nom+" est isocele en "+pA+".") else: print(nom+" est quelconque.") cABC=dAB2+dBC2-dCA2 cBCA=dBC2+dCA2-dAB2 cCAB=dCA2+dAB2-dBC2 if cABC<0 or cBCA<0 or cCAB<0: print(nom+" est obtus.") elif cABC==0: print(nom+" est rectangle en "+pB+".") elif cBCA==0: print(nom+" est rectangle en "+pC+".") elif cCAB==0: print(nom+" est rectangle en "+pA+".") else: print(nom+" est aigu.")
Et un qui affiche la liste des facteurs premiers d’un nombre entier.
def facteurs(n): if type(n) is not int or n<1: raise TypeError("Vous devez entrer un entier positif.") nn=n p=2 div=dict() while nn!=1: while nn%p==0: if p in div: div[p]+=1 else: div[p]=1 nn/=p p+=1 print(str(n)+"="+"*".join("%d^%d"% (p,div[p]) for p in sorted(div)))
Les élèves devaient se contenter de les faire tourner, le deuxième en allant chercher des exercices dans leur manuel.
Il contenait aussi trois scripts à modifier :
Le calcul des coefficient directeur et ordonnée à l’origine d’une droite (non parallèle à l’axe des ordonnées) dont on donnait les coordonnées de deux points.
def distance(A,B): from math import sqrt # la racine carree xA,yA=A xB,yB=B return sqrt(0) # a vous de completer
Le calcul de la longueur d’un segment.
def eqdroite(A,B): xA,yA=A xB,yB=B a=0 # a vous de completer b=0 # a vous de completer return a,b
La détermination du signe d’une fonction affine en fonction de son coefficient directeur et de son ordonnée à l’origine.
def signeaffine(a,b): x=-b/a print("f(x)=%fx+%f est "% (a,b)) if a<0: print("signeacompleter si x<%s et"%x) print("signeacompleter si x>%s."%x) elif a>0: print("signeacompleter si x<%s et"%x) print("signeacompleter si x>%s."%x)
Les passages à modifier ou à compléter étaient des questions de cours de seconde, rien d’insurmontable. Ces trois fonctions répondaient n’importe quoi mais sans se planter, c’était important pour ne pas charger la console d’exécution de messages d’erreur. La partie technique difficile (c’est-à-dire recopier un script sans erreur) était prête et le travail était écrit dans le qscript.
Ce que devait faire le script (avec un exemple d’utilisation et de sortie corrects) était précisé sur la feuille de consignes.
Voici ce que voyaient les élèves dans le navigateur.
L’écran d’accueil.
L’accès à la liste des scripts.
Un exemple de script à modifier.
Le menu d’un script accessible à partir du bouton à droite de son nom.
La console d’exécution.
Et ce qu’ils n’ont pas vu, la coloration syntaxique.
Pour la deuxième heure (fichiers joints python2.pdf et python2.zip), le travail à faire était de même nature mais plus difficile. Ils avaient pu jouer un peu avec la suite de Syracuse et celle de Conway (look and say) avant de s’attaquer à un script plus conséquent qui devait afficher la nature d’un quadrilatère si on lui donnait les noms et coordonnées de ses quatre sommets (dans l’ordre qui va bien). Comme la première heure, ce script tournait sans planter mais était faux.
Ils devaient d’abord modifier un sous-programme qui donnait le carré de la longueur d’un segment et un autre qui calculait les coordonnées d’un vecteur, par exemple :
def distance2(A,B): return (A[0]+B[0])**2+(A[1]+B[1])**2 # Ligne precedente a modifier
Ils avaient à expliquer d’autres lignes de scripts correctes, qui consistaient à calculer les coordonnées de vecteurs, à tester leur égalité puis celle des carrés leurs normes :
# Deux lignes a expliquer (1) vecteur01=vecteur(coord[0],coord[1]) vecteur32=vecteur(coord[3],coord[2])
Petite erreur de ma part, j’aurais pu nommer les vecteurs vecteurAB et vecteurDC, ils ont eu du mal à faire le lien mais il n’y aurait eu plus rien à faire. Le (1) signifie qu’il s’agit du premier bout de script à expliquer dans leur feuille de consignes.
Enfin, ils devaient modifier quelques affichages, c’est-à-dire reconnaître les cas du losange et du rectangle.
Ils étaient invités à tester leur script terminé sur des exercices de leur manuel.
Le script complet
def distance2(A,B): return (A[0]+B[0])**2+(A[1]+B[1])**2 # Ligne precedente a modifier def vecteur(A,B): return B[0]+A[0],B[1]+A[1] # Ligne precedente a modifier def quadrilatere(p0,p1,p2,p3): liste=[p0,p1,p2,p3] coord=[] nom="" for p in liste: coord+=[p[1:]] nom+=p[0] phrase=nom+" est un " # Deux lignes a expliquer (1) vecteur01=vecteur(coord[0],coord[1]) vecteur32=vecteur(coord[3],coord[2]) if vecteur01==vecteur32: # Ligne precedente a expliquer (2) longueur01=distance2(coord[0],coord[1]) longueur12=distance2(coord[1],coord[2]) longueur13=distance2(coord[1],coord[3]) longueur02=distance2(coord[0],coord[2]) if longueur01==longueur12 and longueur13==longueur02: # Ligne precedente a expliquer (3) print(phrase+"carre.") elif longueur01==longueur12: print(phrase+".") # Ligne precedente a modifier elif longueur13==longueur02: print(phrase+".") # Ligne precedente a modifier else: print(phrase+"parallelogramme.") else: print(phrase+"quadrilatere quelconque.")
J’ai aussi tenté l’an dernier un peu de Python en 1STI et l’expérience n’a pas été plus concluante qu’en seconde pour la même raison.
Cette année, j’ai testé le même genre de travail qu’en seconde : une découverte de Python puis un script plus conséquent à modifier.
Lors de la première heure, les élèves avaient à disposition ces scripts fonctionnels (oui, je recycle, fichiers joints naturetriangles.pdf et triangles.zip) :
En revanche, le script à modifier était plus conséquent : il s’agissait de celui donné en seconde sur la nature d’un triangle mais cette fois-ci, il n’était pas fonctionnel. Les élèves devaient modifier un sous-programme qui calculait la distance (donné juste avant) ainsi que quelques lignes dans la fonction principale :
dAB2=distance2(A,B) dBC2=0 # a vous de completer dCA2=0 # a vous de completer
Ou :
if cABC<0 or cBCA<0 or cCAB<0: print(nom+" est a vous de completer.") elif cABC==0: print(nom+" est a vous de completer en "+pB+".")
Le script complet
def triangles(A,B,C): def distance2(A,B): pA,xA,yA=A # le nom d'un point suivi de ses coordonnees pB,xB,yB=B return 0 # a vous de completer pA,xA,yA=A pB,xB,yB=B pC,xC,yC=C dAB2=distance2(A,B) dBC2=0 # a vous de completer dCA2=0 # a vous de completer nom=pA+pB+pC if dAB2==dBC2==dCA2: print(nom+" est a vous de completer.") elif dAB2==dBC2: print(nom+" est a vous de completer en "+pB+".") elif dBC2==dCA2: print(nom+" est a vous de completer en "+""+".") elif dCA2==dAB2: print(nom+" est a vous de completer en "+""+".") else: print(nom+" est quelconque.") cABC=dAB2+dBC2-dCA2 cBCA=0 # a vous de completer cCAB=0 # a vous de completer if cABC<0 or cBCA<0 or cCAB<0: print(nom+" est a vous de completer.") elif cABC==0: print(nom+" est a vous de completer en "+pB+".") elif cBCA==0: print(nom+" est a vous de completer en "+""+".") elif cCAB==0: print(nom+" est a vous de completer en "+""+".") else: print(nom+" est aigu.")
La deuxième heure, moins réussie car plus difficile et surtout plus abstraite pour des élèves de 1STI, leur ont fait utiliser les suites de Syracuse et de Conway puis étudier un script incomplet qui devait afficher les termes successifs de la suite de Robinson qu’on avait vue auparavant en exercice (fichiers joints suites.pdf et robinson.zip).
La suite de Robinson
Il s’agit d’une variante de la suite de Conway où on compte toutes les occurences de chaque chiffre, pas seulement consécutives, ordonnées dans l’ordre. Si son premier terme est 0, les suivants sont 10 (un 0), 1011 (un 0 et un 1), 1031 (un 0 et trois 1), 102113 (à vous)… On remarque qu’à partir d’une dizaine de termes, la suite est périodique, c’est ce que détecte le script fourni aux élèves.
Comme les élèves de seconde, ils devaient expliquer quelques lignes de scripts exactes et en modifier d’autres par exemple dans la fonction qui renvoyait le terme suivant de la suite :
def suivante(chaine): liste=[0 for _ in range(10)] for caractere in chaine: # Que fait ce bloc ? (1) chiffre=int(caractere) liste[chiffre]+=0 # Modifier cette ligne nouvelle="" for chiffre in range(9,-1,-1): # Que fait ce bloc ? (2) if liste[chiffre]>0: nouvelle+=str(liste[0])+str(0) # Modifier cette ligne return "nawak" # Modifier cette ligne
La fonction centrale
def robinson(chaine): chaines=[] compte=0 while chaine not in chaines: # Que fait ce bloc ? (3) chaines+=[chaine] compte+=0 # Modifier cette ligne print("%d %s"%(compte,chaine)) chaine=suivante("0") # Modifier cette ligne index=0 while chaine!=chaines[index]: # Que fait ce bloc ? (4) index+=1 print("%s est au numero %d"%(chaine,index))
Les élèves ne connaissaient pas la calculette mais n’ont pas eu peur de l’émulateur, bien au contraire. Un seul petit point négatif : ils ne pouvaient pas agrandir l’écran d’autant plus que les caractères étaient clairs (ce qui est corrigé aujourd’hui avec en prime une coloration syntaxique) et que le nombre de caractères affichés sur une ligne était limité ce qui empêchait d’avoir une vue plus globale du script. Depuis version 1.7, en bas de l’émulateur on peut agrandir l’écran de la calculette à la taille de la fenêtre du navigateur.
Quant à la notation de ces deux fois deux heures, sur la suggestion d’un collègue, j’ai parsemé la feuille de travail de rectangles gris que je validais en passant dans les rangs, chacun valait un point (5 pour la première, 6 pour la seconde).
Je reprendrai cette manière de travailler la programmation en classe en commençant plus tôt, en allant plus progressivement et plus loin. Le temps de préparation fut plus conséquent puisque les va-et-vient entre le code en C++, la compilation, l’émulateur compilé et la feuille de consignes ont pris du temps mais les élèves en redemandaient…
Suite aux remarques de la rédaction, j’ai visité le site repl.it que je ne connaissais pas, il me semble plus utilisable en classe que ideone. Quant à thonny, il nécessite l’administrateur pour être installé.
J’ai fait la même chose en seconde et en 1S cette année.