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.
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
- en snap !
- ou en Scratch
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.
Commentaires