Python en Mathématiques - Niveau 2

Créer un module

Plus tard ! Les exercices de cette page peuvent (doivent) être réservés à une seconde lecture.

Pourquoi créer un module

Quelques raisons de créer un module dans le cadre de la classe de mathématiques :

  • Pour un programme un peu complexe, on peut vouloir préparer le terrain afin de simplifier la tâche des élèves. On définit alors à l'avance un certain nombre de fonctions dont on aimerait cacher le code aux élèves pour qu'ils se concentrent sur la question posée. Seul le mode d'emploi des fonctions est alors donné aux élèves.
  • On pourrait vouloir franciser le nom de certaines fonctions.
    Par exemple, la fonction logarithme népérien est notée log (comme dans beaucoup de langages). Une simple affectation ln = log encapsulée dans un module permettra de cacher ce type de problème.

Comment créer un module

Créer un module est très simple. En voici un exemple :

  1. Dans un fichier nommé a.py écrire le code suivant :
    
    from math import log
    
    ln = log
    
    def cube(x) :
    	return x*x*x
    
    
  2. Dans un second fichier situé dans le même répertoire, tester le code suivant :
    
    from a import ln, cube
    
    print(ln(100))
    print(cube(2))
    

Vous venez de créer un module contenant une fonction ln() et une fonction cube utilisable sans connaître la manière dont elles ont été implémentées (codées).

Créons un module

Dans le cadre d'exercices sur les vecteurs, on aimerait utiliser un type Point et un type Vecteur.

Pour cela, on définit le code ci-après qu'il est préférable de cacher ce code aux élèves.
Seuls quelques exemples d'utilisation leur seront présentés.

  • Commentaire

Nous ne donnons pas ici d'explication sur ce code mais donnons quelques exemples d'utilisation.
L'objectif est de convaincre que l'on peut utiliser ce code sans comprendre comment il est construit : l'important est d'avoir un mode d'emploi avec quelques exemples.


class Point:
	def __init__(self, abscisse=0, ordonnee=0) :
		self.x = abscisse
		self.y = ordonnee
		
	def __eq__(self, point) :
		return self.x == point.x and self.y == point.y
		
	def __str__(self):
		return  "({}, {})".format(self.x, self.y) 
		
		
class Vecteur:
	def __init__(self, abscisse=0, ordonnee=0) :
		self.x = abscisse
		self.y = ordonnee
		
	def __eq__(self, vecteur) :
		return self.x == vecteur.x and self.y == vecteur.y
	
	def __str__(self):
		return "({}, {}) ".format(self.x, self.y) 
		
 
# exemple d'utilisation :
 
if __name__ == "__main__":
	
	M = Point(3,4)
	N = Point(5,7)
	u = Vecteur(N.x - M.x, N.y - M.y)
	print("Coordonnées du vecteur u :")
	print(u)
	
	A = Point(5,7)
	print("Les points N et A ont-ils mêmes coordonnées ?")
	print(A == N)
	print("Les points M et A ont-ils mêmes coordonnées ?")
	print(A == M)

Question

Écrire un programme qui fera appel aux classes ci-dessus sous forme d'un module et dans lequel on teste une fonction nommée est_plg() prenant en entrée quatre points et renvoyant en sortie True si les quatre points définissent un parallélogramme (dans l'ordre des paramètres) et False sinon.

  • Un code possible
  • Une variante
  • Une autre variante

Dans un fichier appelé geom.py, on place le code fourni :


class Point:
	def __init__(self, abscisse=0, ordonnee=0) :
		self.x = abscisse
		self.y = ordonnee
		
	def __eq__(self, point) :
		return self.x == point.x and self.y == point.y
		
	def __str__(self):
		return  "({}, {})".format(self.x, self.y) 
		
		
class Vecteur:
	def __init__(self, abscisse=0, ordonnee=0) :
		self.x = abscisse
		self.y = ordonnee
		
	def __eq__(self, vecteur) :
		return self.x == vecteur.x and self.y == vecteur.y
	
	def __str__(self):
		return "({}, {}) ".format(self.x, self.y) 
		
 
# exemple d'utilisation :
 
if __name__ == "__main__":
	
	M = Point(3,4)
	N = Point(5,7)
	u = Vecteur(N.x - M.x, N.y - M.y)
	print("Coordonnées du vecteur u :")
	print(u)
	
	A = Point(5,7)
	print("Les points N et A ont-ils même coordonnées ?")
	print(A == N)
	print("Les points M et A ont-ils même coordonnées ?")
	print(A == M)

La partie à partir de if __name__ == "__main__": peut être supprimée.

Le fichier d'utilisation pourrait alors ressembler à ceci :


import geom as g
 
##----- Définition des fonctions -----## 
def vecteur(A, B) :
	return g.Vecteur(B.x - A.x, B.y - A.y)
	
def est_plg(A, B, C, D) :
	v = vecteur(A, B)
	u = vecteur(D, C)
	return v == u
	
	
##----- Tests et interaction -----## 
A = g.Point(0, 0)
B = g.Point(2, 0)
C = g.Point(4, 2)
D = g.Point(2, 2)
E = g.Point(4, 99)
 
print(est_plg(A, B, C, D))
print(est_plg(A, B, C, E))

Une variante pour ce fichier :


from geom import *
 
##----- Définition des fonctions -----## 
def translate(A, u):
	return  Vecteur(A.x + u.x, A.y + u.y)
	
def vecteur(A, B) :
	return  Vecteur(B.x - A.x, B.y - A.y)
	
def est_plg(A, B, C, D) :
	v = vecteur(A, B)
	M = translate(D, v)
	return M == C
	
	
##----- Tests et interaction -----## 
A =  Point(0, 0)
B =  Point(2, 0)
C =  Point(4, 2)
D =  Point(2, 2)
E =  Point(4, 99)

 
print(est_plg(A, B, C, D))
print(est_plg(A, B, C, E))

Une autre variante pour ce fichier d'utilisation :


from geom import *
 
##----- Définition des fonctions -----## 
def milieu(P,Q) :
	mx = 1/2 * (P.x + Q.x)
	my = 1/2 * (P.y + Q.y)
	return Point(mx, my)

def est_plg(A, B, C, D) :
	return milieu(A,C) == milieu(B,D)
	
	
##----- Tests et interaction -----## 
A =  Point(0, 0)
B =  Point(2, 0)
C =  Point(4, 2)
D =  Point(2, 2)
E =  Point(4, 99)


print(est_plg(A, B, C, D))
print(est_plg(A, B, C, E))

Remarque : pour simplifier, les tests sont des tests d'égalité, mais dès que l'on utilise des float, il serait préférable de remplacer l'égalité par un test vérifiant une distance faible entre les résultats. On aura alors un test à True plus souvent :

  • lorsque True doit effectivement être renvoyé,
  • mais également des tests à True dans des cas où les points sont seulement très proches.

Dans tous les cas, cela induit des commentaires à faire aux élèves pour souligner le fait que les nombres en machine ne sont pas les nombres mathématiques...

Un autre module

Les fonctions cos() et sin() s'obtiennent en chargeant le module math. Ces fonctions prennent en argument un nombre en radians.

On aimerait proposer aux élèves des fonctions cosinus et sinus dans lesquelles on puisse indiquer la mesure d'un angle ainsi que son unité ("radians", "rad", "degrés", "degres" ou "deg").

Proposer un module définissant de telles fonctions puis un fichier utilisant les fonctions de ce module.

  • Un code
  • Variante et commentaire

Dans un fichier de nom trigo.py, on écrit par exemple le code suivant :


from math import cos, sin, pi

##----- Définition des fonctions -----##
def cosinus(x, unite):
	if unite == "radians" or unite == "rad" :
		return cos(x)
	elif unite == "degrés" or unite == "degres" or unite == "deg" :
		return cos(x * pi/180)


def sinus(x, unite):
	if unite == "radians" or unite == "rad" :
		return sin(x)
	elif unite == "degrés" or unite == "degres" or unite == "deg" :
		return sin(x * pi/180)


Le fichier d'utilisation pourrait alors ressembler à ceci :


from trigo import cosinus, sinus
from math import pi


##----- Tests et interaction -----##
print(sinus(pi/2, "radians"))
print(sinus(90, 'deg'))

print(cosinus(pi/4, "radians"))
print(cosinus(45, 'deg'))

Dans un fichier de nom trigo.py, on écrit par exemple le code suivant :


from math import cos, sin, pi, radians

##----- Définition des fonctions -----##
def cosinus(x, unite = "radians"):
	if unite == "radians" or unite == "rad" :
		return cos(x)
	elif unite == "degrés" or unite == "degres" or unite == "deg" :
		x = radians(x)
		return cos(x)


def sinus(x, unite = "radians"):
	if unite == "radians" or unite == "rad" :
		return sin(x)
	elif unite == "degrés" or unite == "degres" or unite == "deg" :
		x = radians(x)
		return sin(x)
		
		
		
if __name__ == "__main__":
	print(cosinus(pi/4))
	print(cosinus(45, "deg"))

La fonction radian du module math transforme les degrés en radians.

La déclaration cosinus(x, unite = "radians") donne la valeur "radians" par défaut au paramètre unite, de sorte que si l'on appelle la fonction avec un seul paramètre, le second paramètre (unite) vaut "radians".