Plaidoyer pour la console Python

mardi 7 décembre 2021
par  Alain BUSSER

La console (shell chez Casio) de Python ne fait qu’une chose, mais elle le fait bien :

  1. elle attend que l’utilisateur entre une expression (informatique)
  2. elle évalue cette expression (c’est-à-dire qu’elle détermine sa valeur à l’aide d’une stratégie d’évaluation (informatique) ; en effet une expression a une valeur, c’est connu depuis les encyclopédistes)
  3. elle affiche le résultat de cette évaluation.

Elle le fait de façon répétitive, et son usage permet de familiariser les élèves avec la notion même d’expression, ce qui facilite grandement l’apprentissage ultérieur de Python et même de l’algèbre et de la logique.

>>> 6*7
42
>>> 3e-2
0.03
>>> 2<3<5
True
>>> 4 in range(8)
True
>>> 2+2==4
True
>>> True or not True
True
>>> from math import pi
>>> type(pi)
<class 'float'>
>>> 1/float('inf')
0.0
>>> 

Accès à la console

La console s’appelle souvent shell : on la voit comme une coque séparant le moteur Python de l’utilisateur. En fait l’image du génie d’Aladin est plus parlante :

à ceci près que

  • la console n’exauce pas seulement 3 vœux mais, aveu, autant de vœux qu’on veut
  • les vœux que l’on donne à la console sont en fait des expressions Python à évaluer.

Au lieu de dire « maître quel est le prochain souhait que tu veux que j’exauce ? », le génie se contente d’afficher trois chevrons :

>>>

Unix

Dans un terminal Linux ou Mac, il suffit d’écrire la commande python3 pour transformer la console bash en une console Python :

♟️ python3
Python 3.4.2 (default, Feb  7 2019, 09:32:19) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 6*7
42
>>> 

Numworks

Sur la calculatrice Numworks, on commence par aller vers l’application python :

On sélectionne cette application par appui sur le bouton OK puis on descend avec la flèche vers le bas pour descendre en dessous des scripts :

Un autre appui sur OK suffit alors à ouvrir la console :

Ti

Sur la Ti 83 Premium CE Edition Python, on constate qu’il y a écrit apps au-dessus du bouton résol. En faisant 2nde résol on ouvre donc le menu des applications. Parmi celles-ci on choisit Python (évidemment !) et à ce moment on voit apparaître un menu en bas de l’écran. Dans ce menu, le texte shell apparaît juste au-dessus du bouton trace. En appuyant sur ce bouton, on accède alors au « shell » qui n’est autre que la console Python.

Casio

Sur la Graph 90+E ou la Graph 35+EII, appuyer sur le bouton MENU permet de naviguer parmi les applications. Là évidemment on choisit celle qui s’appelle Python puis on appuye sur EXE. On voit alors un menu en bas de l’écran. Parmi les entrées de ce menu, le mot SHELL est juste au dessus de la touche F4. Un appui sur la touche F4 permet donc de démarrer le « shell », également appelé console Python.

Shell

Dans beaucoup de logiciels permettant de programmer en Python, est présente une fenêtre appelée « shell » et permettant d’interagir avec Python : c’est la fameuse console présentée ici. On la voit notamment dans

  • IDLE
  • PyCharm
  • Spyder
  • Thonny
  • Anaconda
  • Pyzo

etc.

Basthon

En ligne, il y a aussi une console dans Basthon. Et le site repl.it comme son nom l’indique, permettait d’expérimenter sur une console. Hélas, ce site est devenu payant.

Capytale aussi possède une console Python.

Skulpt aussi possède une console.

Gimp

Si vous faites du traitement d’image, le logiciel Gimp a sa console (c’est un filtre photo) appelée python-fu.

Le logiciel Blender aussi a une console Python. On l’ouvre en cliquant sur « Python console », elle s’ouvre alors à la place de la vue 3D, de la timeline etc.

La console Python ne fait qu’une chose, mais cette chose s’avère extrêmement utile pour l’apprentissage simultané de Python, et des mathématiques (en particulier l’algèbre). Dans la suite de cet article, on verra des exemples qui ont déjà été donnés en classe (en particulier en voie technologique) en quelques heures [1].

expressions numériques

Théoriquement, les élèves qui arrivent au lycée savent déjà ce qu’est une expression, puisqu’ils ont eu l’occasion de les manipuler

Dans les deux cas, il faut cliquer sur l’expression (bloc vert) pour voir apparaître dans un phylactère, le résultat de l’évaluation.

En Python, on écrit le « calcul » au clavier, puis on appuie sur la touche « entrée » pour voir affiché le résultat de l’évaluation :

>>> 6*7
42

Entiers

L’addition se note + en Python, cela ne pose pas de poblème. Mais il est bon de laisser aux élèves le temps de se le rappeler. Quant au signe « - », il a deux significations selon qu’on le considère comme un signe (entier négatif) ou une soustraction :

>>> +2
2
>>> 5-2
3
>>> -2
-2
>>> 0-2
-2
>>> 3-5
-2

Alors que les notations + et - sont naturelles pour l’addition et la soustraction, il faut quand même, à un moment, expliquer aux élèves comment on note, en Python, les autres opérations.

Le principe est le même que dans les calculatrices : le nombre zéro est sous-entendu devant le signe de soustraction et -2 désigne le nombre 0-2 en fait.

La multiplication se note par un astérisque en Python. Mais il y a plusieurs divisions possibles, l’une renvoyant un flottant (voir onglet suivant), l’autre renvoyant un entier :

>>> 6*7
42
>>> 22/7
3.142857142857143
>>> 22//7
3
>>> 22%7
1
>>> divmod(22,7)
(3, 1)
>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

Le quotient entier, en Python, se note donc par un double slash. Attention à ne pas s’imaginer qu’il suffise de le dire une seule fois aux élèves ! L’algorithme donnant ce quotient entier (nombre maximum de fois qu’on peut soustraire le dividende au diviseur sans que le résultat soit négatif) est au programme de 2nde. On constate au passage que Python ne sait pas diviser par zéro, ou plutôt qu’il sait qu’on ne peut pas diviser par zéro.

La division euclidienne ne donne pas qu’un quotient, elle donne aussi un reste. Ce reste se note par le symbole « pourcent » en Python. On reverra cette no(ta)tion plus bas, lorsqu’on abordera la divisibilité. Mais déjà, on peut résoudre ce genre de problème :

Sept mille secondes après minuit, quelle heure est-il ?

Déjà, 7000 secondes, cela fait 116 minutes et 40 secondes :

>>> 7000//60
116
>>> 7000%60
40
>>> 116//60
1
>>> 116%60
56

Ensuite, 116 minutes font une heure 56 minutes. La solution de l’exercice est donc une heure cinquante six minutes quarante secondes.

Après les 4 opérations, voici la cinquième : l’exponentiation

>>> 2**3
8
>>> 3**2
9

L’exponentiation se note par un double astérisque en Python, et on peut vérifier que cette opération n’est pas commutative.

L’avantage de la calculatrice est que les élèves apprennent, à leurs dépens (ou plutôt ceux de la calculatrice) à éviter les trop grands nombres :

>>> 2021**2021

C’est aussi l’occasion de vérifier que x0 est égal à 1 et autres souvenirs du collège (notamment sur les priorités opératoires) :

>>> 3**0
1
>>> 10**0
1
>>> 10**2
100
>>> 10**3
1000
>>> 2**3*5**3
1000

Algèbre

Python connaît les règles de priorité opératoire, et les parenthèses. Noter que l’usage de crochets ou accolades en guise de parenthèses extérieures, ne convient pas.

Les exemples suivants peuvent donner lieu à des « questions flash » :

>>> 2*5-7
3
>>> 5*3+4
19
>>> 5+3*4
17
>>> 2*10**2
200
>>> 5*(3+4)
35
>>> (2*3-1)*(5+3*4)
85
>>> (2*3-1)-(5+3*4)
-12
>>> (2+3*(5-2))
11
>>> (2+3*(5-2))*4
44
>>> -5**2
-25
>>> (-5)**2
25

Un énoncé typique serait

À quoi s’évalue l’expression Python suivante ?
>>> 2+3*(5-2)

(voire la version sans chevrons ; pour insister sur la présence d’une expression).

réels

En Python, les nombres réels sont modélisés par des flottants. En première approximation, on peut considérer les flottants comme réels :

>>> -5**2
-25
>>> (-5)**2
25
>>> 3.0
3.0
>>> 2+3
5
>>> 2+3.0
5.0

La convention, typique des calculatrices, de ne pas exiger l’écriture d’un chiffre zéro s’il n’y a pas d’ambigüité, est connue également de Python :

>>> .2+.3
0.5
>>> .1+.2
0.30000000000000004

On voit sur l’exemple ci-dessus que certains décimaux ne peuvent être représentés exactement comme des flottants.

Python connaît l’écriture scientifique :

>>> 2*10**3
2000
>>> 2e3
2000.0
>>> 2e-3
0.002

Là encore on peut multiplier les questions flash, cette fois-ci sur les ordres de grandeur et les écritures scientifiques :

>>> 1.25e7*3.2e-5
400.0

(corrigé sans Python : 1,25×107*3,2×10-5=1,25×3,2×107×10-5=4×107-5=4×102=400)

En apparence, Python ne connaît pas le nombre e. En fait il suffit de l’importer depuis le module math pour bénéficier d’une valeur approchée :

>>> e
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'e' is not defined
>>> from math import e
>>> e
2.718281828459045

En soumettant à la fonction float l’argument « inf » on construit un flottant particulier, noté ∞ :

>>> float('inf')+2
inf
>>> float('inf')-2
inf
>>> float('inf')*2
inf
>>> float('inf')/2
inf

On lit que ∞+2=∞-2=∞×2=∞/2=∞. En fait d’autres limites usuelles de fonctions non moins usuelles apparaissent :

>>> 1/float('inf')
0.0
>>> 0/float('inf')
0.0
>>> float('inf')**2
inf
>>> from math import exp
>>> exp(float('inf'))
inf
>>> exp(-float('inf'))
0.0

Python connaît même certaines formes indéterminées :

>>> float('inf')-float('inf')
nan
>>> float('inf')*0
nan

complexes

Comme la console Python peut rester utile après la 2nde, on peut aussi s’en servir pour effectuer des calculs sur les nombres complexes. Il suffit de savoir que le nombre i est appelé 1j en Python :

>>> 1+2j
(1+2j)
>>> (1j)**2
(-1+0j)
>>> 1+2j+3-5j
(4-3j)
>>> (1+2j)*(3-5j)
(13+1j)
>>> (1+1j)/(4+3j)
(0.28+0.04j)

Pour connaître la partie réelle, la partie imaginaire (deux réels), le conjugué et le module de 4+3i, on a essentiellement à se souvenir que « module » se dit abs en Python :

>>> (4+3j).real
4.0
>>> (4+3j).imag
3.0
>>> (4+3j).conjugate()
(4-3j)
>>> abs(4+3j)
5.0

En évaluant de nombreuses expressions faisant apparaître des nombres complexes, les élèves de STI2D ont plus de chance de pouvoir conjecturer (donc mémoriser) le fait que si deux nombres complexes sont conjugués, alors leur somme et leur produit sont réels.

variables

Pour entrer l’expression (768/1024+1)*((768/1024)**2-5*768/1024+2)*(768/1024-1) il peut être commode de mémoriser une fois pour toutes que x=768/1024 et ensuite évaluer l’expression (x+1)*(x**2-5*x+2)*(x-1) afin de ne pas trop souvent écrire 768/1024 :

>>> x = 768/1024
>>> (x+1)*(x**2-5*x+2)*(x-1)
0.51953125

L’association entre le nom x et la valeur 768/1024 est une variable. L’espace des variables (globales) peut être consultée depuis la console :

>>> globals()
{'x': 0.75, ......}

None

Associer une valeur (comme 768/1024) à une variable, c’est faire une affectation. Ce genre d’expression ne s’affiche pas dans la console. En fait elle s’évalue à None et c’est None qui ne s’affiche pas :

>>> None
>>> from math import pi
>>> from fractions import *
>>> Fraction(768,1024)
Fraction(3, 4)

Une expression qui s’évalue à None (et donc ne s’affiche pas) s’appelle une instruction. On en a déjà vu deux sortes :

  • l’importation de fonctions ou de constantes depuis un module
  • l’affectation d’une variable

On en verra d’autres plus bas, comme la définition d’une fonction...

En tout cas, l’affectation d’une variable consiste à forcer sa valeur à être le résultat de l’évaluation d’une expression. On voit que l’affectation se note par un signe d’égalité (choix malheureux) en Python.

>>> x = 2
>>> globals()
{'x': 2, ......}
>>> x = 5
>>> globals()
{'x': 5, ......}

évaluation

Les variables sont des expressions comme les autres, on peut donc les évaluer.

Pour évaluer une variable, la règle est simple : une variable s’évalue à sa valeur :

>>> x = 5
>>> globals()
{'x': 5, ......}
>>> globals()['x']
5

Lorsque la console Python voit un nom de variable (comme x), elle va donc l’évaluer en regardant dans le dictionnaire ce que signifie ce nom x et comme dans le dictionnaire globals(), il est rappelé que x vaut 5, la console évalue x à 5 :

>>> x = 5
>>> x
5
>>> x+1
6
>>> (x+1)*(x-1)
24
>>> 2**x
32
>>> x
5

Comme on le voit, il suffit donc d’entrer le nom d’une variable pour que la console donne sa valeur, et cela ne modifie pas la valeur de la variable.

Par exemple, pour incrémenter un compteur, il faut non seulement calculer la somme entre ce compteur et 1, mais mettre le résultat de l’addition dans le compteur :

>>> compteur = 0
>>> compteur + 1
1
>>> compteur
0
>>> compteur = compteur +1
>>> compteur
1

underscore

Dans la console, il y a une variable spéciale, dont le nom est une espace soulignée (ou « tiret du 8 », en anglais underscore) et qui mémorise la dernière expression évaluée. On peut s’en servir comme compteur, en évaluant répétitivement sa somme avec 1 :

>>> 0
0
>>> _
0
>>> _+1
1
>>> _+1
2
>>> _+1
3
>>> _+1
4
>>> _+1
5

En fait il s’agit ici d’un cas particulier de suite arithmétique dont la raison est 1, mais d’autres suites arithmétiques peuvent être calculées ainsi. Et même des suites géométriques, ou plus compliquées, comme celle-ci qui converge vers le nombre d’or :

>>> 1
1
>>> 1+1/_
2.0
>>> 1+1/_
1.5
>>> 1+1/_
1.6666666666666665
>>> 1+1/_
1.6
>>> 1+1/_
1.625
>>> 1+1/_
1.6153846153846154
>>> 1+1/_
1.619047619047619
>>> 1+1/_
1.6176470588235294
>>> 1+1/_
1.6181818181818182
>>> 1+1/_
1.6179775280898876
>>> 1+1/_
1.6180555555555556
>>> 1+1/_
1.6180257510729614
>>> 1+1/_
1.6180371352785146

types

La fonction type permet de connaître le type d’un objet. Avec un nombre elle s’évalue en général à int (si le nombre est entier) ou float (sinon) :

>>> type(3)
<class 'int'>
>>> type(4/2)
<class 'float'>
>>> type(5.2)
<class 'float'>
>>> type(pi)
<class 'float'>

On verra plus bas d’autres types (booléens, ensembles, listes...).

Par extension, le type de la valeur d’une variable (ce à quoi elle s’évalue, vue comme expression) est appelé type de la variable.

logique

Les expressions ne sont pas toutes numériques. Les expressions logiques sont particulièrement utiles en Python.

ordre

Python connaît les relations d’ordre et même les encadrements :

>>> 2+2 == 4
True
>>> 2+2 == 5
False
>>> 2 != 3
True
>>> 2 < 3
True
>>> 2 < 3 < 5
True
>>> 2 <= 3
True
>>> 2 < 2
False
>>> 2 <= 2
True

On remarque que l’égalité est notée par un double signe égal, en effet le simple signe d’égalité a déjà été pris pour noter l’affectation comme on l’a vu dans la partie sur les variables.

Booléens

La logique aristotélicienne est également à la portée de Python.

négation

>>> not True
False
>>> not False
True

conjonction

>>> False and False
False
>>> False and True
False
>>> True and False
False
>>> True and True
True

Disjonction

>>> False or False
False
>>> False or True
True
>>> True or False
True
>>> True or True
True

range

Une relation importante est celle d’appartenance. Elle s’applique entre entiers et collections d’entiers comme range :

>>> range(5)
range(0, 5)
>>> -1 in range(5)
False
>>> 0 in range(5)
True
>>> 1 in range(5)
True
>>> 2 in range(5)
True
>>> 3 in range(5)
True
>>> 4 in range(5)
True
>>> 5 in range(5)
False
>>> 6 in range(5)
False
>>> 1.25 in range(5)
False

Faire évaluer par les élèves, plusieurs dizaines d’expressions de ce genre, est un bon moyen de les aider à conceptualiser la notion de « range », ce qui s’avèrera utile par la suite lorsqu’on abordera les boucles.

Un autre moyen de visualiser un « range » est de lui appliquer la fonction list (voir plus bas) :

>>> list(range(5))
[0, 1, 2, 3, 4]

divisibilité

Le fait que l’entier a est divisible par l’entier b se voit au reste de la division euclidienne de a par b : la divisibilité est caractérisée par la nullité de ce reste euclidien.

Par exemple pour voir si des nombres sont pairs :

>>> 1%2 == 0
False
>>> 3%2 == 0
False
>>> 2021%2 == 0
False
>>> 100%2 == 0
True

Pour voir si des nombres sont divisibles par 7 :

>>> 100%7 == 0
False
>>> 49%7 == 0
True
>>> 21%7 == 0
True
>>> 22%7 == 0
False
>>> 2021%7 == 0
False

Et pour voir si des nombres sont divisibles à la fois par 5 et par 7 :

>>> 35%5==0 and 35%7==0
True
>>> 45%5==0 and 45%7==0
False
>>> 135%5==0 and 135%7==0
False

On aborde ici la notion de diviseurs communs :

>>> 24%8==0 and 16%8==0
True
>>> 24%6==0 and 16%6==0
False
>>> 24%1==0 and 16%1==0
True
>>> 24%4==0 and 16%4==0
True

On verra plus bas, dans la partie sur les listes, ce qu’on peut faire avec les diviseurs communs.

Hasard

Les simulations du hasard sont dans le module random (mot anglais issu du vieux français, qui signifie ... hasard !) :

>>> from random import *

Un dé

Pour simuler le lancer d’un dé, il y a la fonction randint. On lui fournit les bornes (typiquement 1 et 6) :

>>> from random import randint
>>> randint(1,6)
4
>>> randint(1,6)
4
>>> randint(1,6)
6
>>> randint(1,6)
5
>>> randint(1,6)
6
>>> randint(1,6)
1
>>> randint(1,6)
5

Cela permet de simuler des dés à 4 faces, 8 faces, 12 faces, 20 faces comme dans les jeux de rôle (ou Mathador), mais aussi des dés difficiles à réaliser comme par exemple à 13 faces :

>>> randint(1,13)
8
>>> randint(1,13)
5
>>> randint(1,13)
5
>>> randint(1,13)
1

Deux dés

Pour jouer à des jeux de déplacement comme le jeu de l’oye, il suffit d’additionner les résultats de lancers de dés :

>>> randint(1,6) + randint(1,6)
12
>>> randint(1,6) + randint(1,6)
8
>>> randint(1,6) + randint(1,6)
7
>>> randint(1,6) + randint(1,6)
10
>>> randint(1,6) + randint(1,6)
9
>>> randint(1,6) + randint(1,6)
4
>>> randint(1,6) + randint(1,6)
8
>>> randint(1,6) + randint(1,6)
6
>>> randint(1,6) + randint(1,6)
7

On peut avec cette technique, explorer le problème du Duc de Toscane ou d’autres jeux comme le senet où on lançait des bâtons tombant sur pile ou face :

>>> randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)
1
>>> randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)
3
>>> randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)
1
>>> randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)
5
>>> randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)
5
>>> randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)
4
>>> randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)
4
>>> randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)+randint(0,1)
1

probabilités

On lance un dé, mais on essaye de savoir quelles sont les chances que l’on a, d’avoir un résultat de moins que 5. Pour cela on définit les événements

  • Ω (univers de probabilité)
  • A « le dé donne moins que 5 »
  • B « le dé donne un résultat impair » :
>>> Omega = {1,2,3,4,5,6}
>>> A = {1,2,3,4}
>>> B = {1,3,5}

Alors il est possible de calculer les intersection, réunion et contraire d’événements :

>>> A.intersection(B)
{1, 3}
>>> A.union(B)
{1, 2, 3, 4, 5}
>>> Omega.difference(A)
{5, 6}

Euler définissait une probabilité comme « quotient du nombre de cas favorables par le nombre de cas possibles ». Il est donc possible avec la console de calculer P(A) :

>>> cas_favorables = len(A)
>>> cas_possibles = len(Omega)
>>> cas_favorables/cas_possibles
0.6666666666666666

Buffon

Pour simuler l’aiguille de Buffon, on a intérêt à utiliser la fonction random du module éponyme :

>>> from math import pi
>>> from random import random
>>> random()
0.5280980025290867
>>> random()<2/pi
False
>>> random()<2/pi
True
>>> random()<2/pi
False
>>> random()<2/pi
False
>>> random()<2/pi
True
>>> random()<2/pi
False
>>> random()<2/pi
True
>>> random()<2/pi
True
>>> random()<2/pi
True

fonctions

Au bout de quelques heures passées à évaluer des expressions dans la console, les élèves peuvent décrire ce qu’est une expression :

  • un nombre, un booléen sont des expressions
  • une variable est une expression
  • la somme, la différence, le produit, le quotient de deux expressions sont des expressions
  • une expression entre parenthèses reste une expression
  • en appliquant une fonction à une expression, on obtient une expression

Et comme disait Gödel, « rien d’autre n’est une expression, que ce qui est décrit ci-dessus ».

Les fonctions déjà utilisées ci-dessus sont abs (module d’un complexe), exp (exponentielle de base e), float (conversion en flottant), globals (espace des variables), range (voir plus bas les listes) et type (type d’un objet, d’une variable). En plus des fonctions vues en probabilité : random, randint et len (longueur).

Maths

Python ne semble, à première vue, pas très fort en trigonométrie :

>>> cos(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'cos' is not defined
>>> from math import cos
>>> cos(0)
1.0
>>> cos(90)
-0.4480736161291701

En fait, lorsqu’une fonction n’est pas disponible dans la console, c’est souvent parce qu’elle se trouve dans un module et il faut d’abord importer ce module pour pouvoir appeler la fonction. Pour les maths, on s’en doute, le module math est approprié. Donc pour faire des maths en Python, il faut mieux commencer par importer tout ce qui est dans le module math :

>>> from math import *
>>> cos(radians(90))
6.123233995736766e-17
>>> cos(pi/2)
6.123233995736766e-17

Un exemple important est la racine carrée (square root en anglais) :

>>> sqrt(8)
2.8284271247461903
>>> 2*sqrt(2)
2.8284271247461903
>>> sqrt(25)
5.0
>>> sqrt(25) == 5
True
>>> sqrt(float('inf'))
inf
>>> sqrt(2)/2
0.7071067811865476
>>> sin(pi/4)
0.7071067811865475

Pour calculer des distances euclidiennes, on a besoin de la racine de la somme des carrés de deux nombres. Le mot hypot est en fait le début de hypoténuse :

>>> hypot(4,3)
5.0
>>> hypot(12,5)
13.0
>>> hypot(1,1)
1.4142135623730951

Le logarithme népérien ne se note pas ln mais log :

>>> e
2.718281828459045
>>> exp(1)
2.718281828459045
>>> log(e)
1.0
>>> log(1/e)
-1.0

IMC

Pour calculer un IMC avec Python, on a un problème :

>>> imc(1.8,82)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'imc' is not defined

La fonction imc n’existe pas en Python. Le module imc non plus :

>>> from imc import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'imc'

C’est maintenant, et maintenant seulement, qu’on va utiliser autre chose que la console [2] : on va le créer, ce module imc. Pour cela, on passe à un éditeur de texte et on y tape le code suivant :

def imc(taille,masse):
    return masse/taille**2

puis on l’enregistre sous le nom imc.py et ensuite on peut dans la console, calculer des IMC :

>>> from imc import *
>>> imc(1.8,82)
25.30864197530864

Docteur

On peut améliorer le module pour maintenant utiliser la fonction qu’on vient de définir :

def imc(taille,masse):
    return masse/taille**2


def docteur(taille,masse):
    i = imc(taille,masse)
    s = "le patient "
    if 18 <= i <= 25:
        s = s + "est sain"
    elif i < 18:
        s = s + "doit prendre du poids"
    else:
        s = s + "doit perdre du poids"
    return s

Cela permet de simuler, dans la console, un nutritionniste virtuel (il reste à effectuer les mesures sur les différents patients) :

>>> from imc import *
>>> docteur(1.8,82)
'le patient doit perdre du poids'
>>> docteur(1.85,81)
'le patient est sain'
>>> docteur(1.87,72)
'le patient est sain'
>>> docteur(1.87,65)
'le patient est sain'
>>> docteur(1.87,58)
'le patient doit prendre du poids'

Cette partie de l’activité a du succès en 1re ST2S ; elle permet de montrer l’utilité des fonctions mais aussi la manière dont on s’en sert (syntaxe). Elle met en valeur l’interactivité de la console qui évite d’avoir à entrer des données pour un input souvent inutile et handicapant.

Loi normale

Voici un extrait du sujet de bac STL 2019 :

Dans une ville, un cardiologue s’intéresse à la tension artérielle (systolique), mesurée en millimètres de mercure (mmHg), des femmes de plus de 60 ans.

Partie A

On note T la variable aléatoire qui, à chaque dossier médical d’une femme de la ville de plus de 60 ans, associe la tension artérielle de cette femme mesurée en mmHg. On suppose que T suit la loi normale d’espérance µ = 134 et d’écart-type σ = 8,5.
1. Le cardiologue choisit au hasard le dossier médical d’une femme de plus de 60 ans parmi les dossiers médicaux des femmes de la ville.
a. Quelle est la probabilité que la tension artérielle de cette femme soit comprise entre 130 et 140mmHg ? On donnera la valeur arrondie au millième.
b. Quelle est la probabilité que la tension artérielle de cette femme soit supérieure à 140mmHg ? On donnera la valeur arrondie au millième.

Pour résoudre ce problème avec la console de Python, il faut savoir que

  • le module math possède une fonction erf
  • la fonction erf(x/√2)/2 est la fonction de répartition de la variable aléatoire normale centrée réduite
  • on peut toujours centrer et réduire une variable aléatoire en
    • lui soustrayant son espérance µ
    • divisant le résultat par l’écart-type σ

On va donc commencer par

>>> from math import *
>>> def Z(x): return erf(x/sqrt(2))/2
... 
>>> def F(x): return Z((x-134)/8.5)
... 

La solution du sujet de bac est alors donnée par

>>> F(140)-F(130)
0.44090194332781
>>> 1-F(140)
0.7401306513767114

Ou mieux encore (autant déléguer tout le travail à Python) :

>>> round(F(140)-F(130),3)
0.441
>>> round(1-F(140),3)
0.74

boucles

Comment faire des boucles sans utiliser print ?

En fait, on peut aussi utiliser print dans la console :

>>> for x in range(8): print(x**2)
... 
0
1
4
9
16
25
36
49

Mais il existe des moyens de ne pas replonger dans l’addiction au print. Ils ne sont pas au programme de 2nde mais quelqu’un qui a fait en 2nde toutes les activités présentées ci-dessus (sauf l’exponentielle) aura passé plusieurs heures et aura probablement envie de passer à autre chose que des print...

listes

Si on veut la liste des carrés inférieurs à 64, plutôt que la boucle avec print montrée dans l’onglet précédent, on peut regrouper ces carrés en une liste de carrés :

>>> [x**2 for x in range(8)]
[0, 1, 4, 9, 16, 25, 36, 49]

C’est bien plus concis que le print dans des boucles, et il s’agit toujours d’une expression, à laquelle on peut appliquer des fonctions comme

>>> liste = [x**2 for x in range(8)]
>>> len(liste)
8
>>> sum(liste)
140
>>> sum(liste)/len(liste)
17.5
>>> m = len(liste)//2
>>> m
4
>>> (liste[m]+liste[m+1])/2
20.5

où on apprend, entre autres, que le carré médian est 20,5 alors que le carré moyen n’est que 17,5.

range

La fonction list permet de convertir son argument en liste. Par exemple avec un range :

>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(3,8))
[3, 4, 5, 6, 7]
>>> list(range(13,5,-1))
[13, 12, 11, 10, 9, 8, 7, 6]

Remarque : il est possible d’éviter l’usage de cette fonction, par les listes en compréhension :

>>> list(range(5))
[0, 1, 2, 3, 4]
>>> [x for x in range(5)]
[0, 1, 2, 3, 4]

Du coup les expériences menées précédemment avec des booléens sur range, sont nettement accélérées :

>>> list(range(3,8))
[3, 4, 5, 6, 7]
>>> list(range(13,5,-1))
[13, 12, 11, 10, 9, 8, 7, 6]
>>> list(range(5))
[0, 1, 2, 3, 4]
>>> [x for x in range(5)]
[0, 1, 2, 3, 4]

Les compréhensions permettent de calculer des tables, comme par exemple cette table trigonométrique :

>>> X = [x for x in range(0,93,3)]
>>> Y = [cos(radians(x)) for x in X]
>>> X,Y

Allée des ifs

Avec les listes en compréhension, certaines des activités précédentes peuvent être simplifiées. Par exemple l’aiguille de buffon :

>>> [random()<2/pi for _ in range(10)]
[True, True, False, True, True, True, True, True, False, False]
>>> ([random()<2/pi for _ in range(100)]).count(True)
62
>>> ([random()<2/pi for _ in range(1000)]).count(True)/1000
0.65
>>> 2/([random()<2/pi for _ in range(10000)]).count(True)*10000
3.1167212092878294

divisibilité

Une fois qu’on sait comment construire des listes en compréhensions, on revoit le programme de cycle 4 d’une manière pythoniennement rapide.

Listes de diviseurs

On a vu dans la partie sur les booléens, comment voir si un nombre divise un autre. En constatant qu’aucun diviseur de n n’est plus grand que n, on définit la fonction

>>> def ld(n): return [d for d in range(1,n+1) if n%d==0]
... 
>>> ld(12)
[1, 2, 3, 4, 6, 12]

Ensuite on s’intéresse au nombre de diviseurs :

>>> def nd(n): return len(ld(n))
... 
>>> nd(13)
2
>>> [nd(n) for n in range(1,20)]
[1, 2, 2, 3, 2, 4, 2, 4, 3, 4, 2, 6, 2, 4, 4, 5, 2, 6, 2]

ce qui permet d’aborder la notion de nombres premiers (ceux dont l’image par la fonction nd est 2).

Puis on s’intéresse aux diviseurs communs à deux entiers :

>>> def cd(a,b): return [x for x in ld(a) if x in ld(b)]
... 
>>> cd(24,16)
[1, 2, 4, 8]

Enfin, la fonction max permet d’isoler le plus grand des diviseurs communs :

>>> def pgcd(a,b): return max(cd(a,b))
... 
>>> pgcd(24,16)
8

turtle

On peut même faire de la robotique dans la console, avec le module turtle.

L’écran où se font les dessins de la tortue s’ouvre en entrant dans la console

>>> from turtle import *
>>> shape('turtle')
>>> reset()

triangle

Une erreur classique avec la tortue est l’oubli de tourner non pas de 60° mais de son supplémentaire pour dessiner un triangle équilatéral (ligne 3 ci-dessous). Alors plutôt que tout recommencer, on peut rajouter (ligne 4) une rotation de 60° pour avoir la bonne orientation de la tortue :

>>> reset()
>>> forward(50)
>>> left(60)
>>> left(60)
>>> forward(50)
>>> left(120)
>>> forward(50)

vecteurs

On peut additionner, soustraire des vecteurs, multiplier un vecteur par un réel, multiplier scalairement deux vecteurs avec la tortue :

>>> u = Vec2D(4,3)
>>> v = Vec2D(5,-1)
>>> u+v
(9.00,2.00)
>>> u-v
(-1.00,4.00)
>>> u*v
17
>>> 3*u
(12.00,9.00)

On peut aussi faire tourner un vecteur d’un certain angle en degrés :

>>> u.rotate(30)
(1.96,4.60)
>>> u
(4.00,3.00)
>>> u.rotate(90)
(-3.00,4.00)

on peut comparer le produit des normes avec le produit scalaire :

>>> abs(u)
5.0
>>> abs(v)
5.0990195135927845
>>> abs(u)*abs(v)
25.495097567963924
>>> u*v
17
>>> u*v/abs(u)/abs(v)
0.6667948594698258
>>> acos(_)
0.840896668643165
>>> degrees(_)
48.17983011986423

Où l’on apprend qu’entre les vecteurs (4,3) et (5,-1) il y a environ 48°.

On peut aussi calculer les coordonnées du milieu d’un segment :

>>> (u+v)*.5
(4.50,1.00)

On peut aussi tester si des vecteurs sont colinéaires :

>>> def sont_colin(u,v): return abs(u*v)==abs(u)*abs(v)
... 
>>> sont_colin(u,v)
False
>>> sont_colin(u,3*u)
True
>>> sont_colin(u,-u)
True

fonctions

La tortue sait aussi représenter graphiquement des fonctions, par exemple des arcs de parabole :

>>> reset()
>>> for x in range(100): goto(x,x**2/100)
... 

des arcs d’hyperbole :

>>> reset()
>>> for x in range(1,100): goto(x,100/x)
... 

des vagues :

>>> reset()
>>> for x in range(1,300): goto(x,10*sin(x/10))
... 

courbes

Les courbes paramétrées sont également à la portée de la tortue de Python.

>>> reset()
>>> penup()
>>> goto(200,0)
>>> pendown()
>>> for t in range(360): goto(200*cos(3*radians(t)),200*sin(2*radians(t)))
... 

des spirales :

>>> reset()
>>> for t in range(100): goto(t*cos(10*t),t*sin(10*t))
... 

En résumé, évaluer des expressions dans la console Python

  • prend plusieurs heures/élève si on veut le faire bien et solidement
  • permet de mieux comprendre la notion de fonction
  • doit être fait avant toute autre activité Python
  • plaît aux élèves de la voie technologique

Comme il s’agit bien de mettre Python au service des maths et non l’inverse, je ne saurais trop recommander ce genre d’activités (qui peuvent ensuite être déclinées en questions flash) surtout dans les classes dites difficiles.


[1et sans un seul print !

[2mais toujours pas de print !


Erreur d’exécution plugins/auto/sarkaspip/v4.1.0/noisettes/document/inc_images_jointes.html

Commentaires