Dans cette seconde partie, nous allons voir l'utilisation des classes dans un cas concrêt : Apprendre à Python à travailler sur les polynomes.
Un exemple valant mieux qu'un long discours, supposons que je sois en train de développer un programme permettant de travailler sur les polynômes.
Je peux définir un objet représentant un polynôme en général. On peut choisir de représenter les coefficients par une liste de nombres, qui sera donc une propriété de notre classe et définir une méthode permettant de calculer le degré du polynôme.
Avec ces conventions, la liste [1,2,3] représente le polynôme $1+2x+3x^2$.
Voici le code définissant la classe Polynome avec une méthode pour calculer le degré et une autre pour calculer une valeur en un réel $x$
class Polynome :
"""Représentation d'un polynome à coefficients réels"""
def __init__(self, liste_coeffs = [0]) :
"""Initialisation des coeffs, polynome nul par défaut"""
self.coeffs = liste_coeffs
def deg(self) :
"""Degré du polynome"""
return len(self.coeffs)-1
def valeur(self, x) :
"""Calcule P(x)"""
val = self.coeffs[0]
power = 1
for k in range(1, len(self.coeffs)) :
power = power * x
val = val + self.coeffs[k]*power
return val
L'objet Polynome() que nous venons de créer possède
L'accès à la propriété coeffs de notre classe se fait au travers de la variable self.coeffs
p = Polynome([0, 2, 3, 1])
print("P est de degré ",p.deg())
print("P(10)=",p.valeur(10))
print("Les coeffs de P sont ",p.coeffs)
Pour afficher un polynôme, la commande print() ne donne pas le résultat attendu :
print(p)
Pour parvenir au résultat attendu, on peut surcharger la fonction print(). Plus précisément, on peut indiquer à Python comment convertir un polynôme en chaîne de caractères, ce que fera ensuite automatiquement la commande print().
Pour cela, on ajoutera la méthode __str__() dans la définition de la classe Polynome(). Celle-ci est un peu longue à écrire mais ce qu'il faut comprendre ici, c'est le principe de l'ajout de cette fonction.
class Polynome :
"""Représentation d'un polynome à coefficients réels"""
def __init__(self, liste_coeffs = [0]) :
"""Initialisation des coeffs, polynome nul par défaut"""
self.coeffs = liste_coeffs
def deg(self) :
"""Degré du polynome"""
return len(self.coeffs)-1
def valeur(self, x) :
"""Calcule P(x)"""
val = self.coeffs[0]
power = 1
for k in range(1, len(self.coeffs)) :
power = power * x
val = val + self.coeffs[k]*power
return val
def __str__(self) :
""" Convertit le polynome en chaine pour affichage"""
chaine=""
k = 0
# recherche du premier coefficient non nul
while self.coeffs[k] == 0 :
k = k+1
# écriture du terme de plus petit degré
if k == 0 :
if self.coeffs[k] != 0 :
chaine = str(self.coeffs[k])
elif k == 1 :
if self.coeffs[k] == 1 :
chaine = "X"
elif self.coeffs[k] != 0 :
chaine = str(self.coeffs[k]) + "X"
else :
if self.coeffs[k] == 1 :
chaine = "X^" + str(k)
elif self.coeffs[k] != 0 :
chaine = str(self.coeffs[k]) + "X^"+str(k)
# écriture des termes suivants
for i in range(k+1, len(self.coeffs)) :
if self.coeffs[i] == 1 :
if i == 1 :
chaine = chaine + " + " + "X"
else :
chaine = chaine + " + " + "X^"+str(i)
elif self.coeffs[i] > 0 :
if i == 1 :
chaine = chaine + " + " + str(self.coeffs[i]) + "X"
else :
chaine = chaine + " + " + str(self.coeffs[i]) + "X^"+str(i)
elif self.coeffs[i] < 0 :
if i == 1 :
chaine = chaine + " - " + str(abs(self.coeffs[i])) + "X"
else :
chaine = chaine + " - " + str(abs(self.coeffs[i])) + "X^"+str(i)
return chaine
p = Polynome([0, 2, 3, 1])
print(p)
Soit les polynômes $P(x)=2x+3x^2+x^3$ et $Q(x)=x^6$. Pour obtenir le polynôme $P+Q$, on aimerait utiliser simplement l'opérateur '+'. Mais voilà ce qui arrive
p = Polynome([0, 2, 3, 1])
q = Polynome([0, 0, 0, 0, 0, 0, 1])
s = p + q
print(s)
Là encore, pour résoudre ce problème, on peut surcharger l'addition en définissant la méthode spéciale __add__(), c'est-à-dire apprendre à Python comment on additionne deux polynômes.
Nous complétons donc à nouveau notre classe Polynomes()
class Polynome :
"""Représentation d'un polynome à coefficients réels"""
def __init__(self, liste_coeffs = [0]) :
"""Initialisation des coeffs, polynome nul par défaut"""
self.coeffs = liste_coeffs
def deg(self) :
"""Degré du polynome"""
return len(self.coeffs)-1
def valeur(self, x) :
"""Calcule P(x)"""
val = self.coeffs[0]
power = 1
for k in range(1, len(self.coeffs)) :
power = power * x
val = val + self.coeffs[k]*power
return val
def __str__(self) :
""" Convertit le polynome en chaine pour affichage"""
chaine=""
k = 0
# recherche du premier coefficient non nul
while self.coeffs[k] == 0 :
k = k+1
# écriture du terme de plus petit degré
if k == 0 :
if self.coeffs[k] != 0 :
chaine = str(self.coeffs[k])
elif k == 1 :
if self.coeffs[k] == 1 :
chaine = "X"
elif self.coeffs[k] != 0 :
chaine = str(self.coeffs[k]) + "X"
else :
if self.coeffs[k] == 1 :
chaine = "X^" + str(k)
elif self.coeffs[k] != 0 :
chaine = str(self.coeffs[k]) + "X^"+str(k)
# écriture des termes suivants
for i in range(k+1, len(self.coeffs)) :
if self.coeffs[i] == 1 :
if i == 1 :
chaine = chaine + " + " + "X"
else :
chaine = chaine + " + " + "X^"+str(i)
elif self.coeffs[i] > 0 :
if i == 1 :
chaine = chaine + " + " + str(self.coeffs[i]) + "X"
else :
chaine = chaine + " + " + str(self.coeffs[i]) + "X^"+str(i)
elif self.coeffs[i] < 0 :
if i == 1 :
chaine = chaine + " - " + str(abs(self.coeffs[i])) + "X"
else :
chaine = chaine + " - " + str(abs(self.coeffs[i])) + "X^"+str(i)
return chaine
def __add__(self, poly) :
"""retourne la somme de deux polynomes"""
coeffs_somme=[]
if self.deg() <= poly.deg() :
for i in range(self.deg()+1) :
coeffs_somme.append(self.coeffs[i] + poly.coeffs[i])
for i in range(self.deg()+1, poly.deg()+1) :
coeffs_somme.append(poly.coeffs[i])
else :
for i in range(poly.deg()+1) :
coeffs_somme.append(self.coeffs[i] + poly.coeffs[i])
for i in range(poly.deg()+1, self.deg()+1) :
coeffs_somme.append(self.coeffs[i])
somme = Polynome(coeffs_somme)
return somme
Essayons à nouveau l'addition de nos polynômes
p = Polynome([0, 2, 3, 1])
q = Polynome([0, 0, 0, 0, 0, 0, 1])
s = p + q
print(s)
On peut également définir des méthodes __sub__() pour la soustraction, __mul__() pour la multiplication, __truediv__() pour la division, etc...
D'autres méthodes spéciales existent : la liste complète est disponible dans la documentation de Python.
L'un des grands avantages des objets est l'héritage. Cela permet de personaliser une classe en héritant des propriétés et méthodes d'une autre classe.
Nous allons en voir un exemple en créant une classe Trinome() pour le cas particulier des polynômes du second degré. En effet, un polynome du second degré étant un cas particulier de polynome, nous ne voulons pas réécrire tout le code que nous venons de créer, notamment pour l'affichage et l'addition. Néanmoins, pour le trinome, nous savons calculer les racines et nous souhaitons donc enrichir notre classe Trinome() avec une méthode suplémentaire appelée racines(). Celle-ci utilisera une nouvelle propriété delta créée lors de l'initialisation de notre classe.
Pour éviter de réécrire toutes les fonctions propres aux polynomes, nous allons faire hériter notre classe Trinome() de la classe Polynomes().
Regardez plutôt avec quelle facilité à présent nous allons créer notre classe Trinome() :
class Trinome(Polynome) :
""" Représentation des polynomes du second degré"""
def __init__(self, liste_coeffs=[0,0,1]) :
""" Initialisation d'un trinome, x^2 par défaut """
Polynome.__init__(self, liste_coeffs) # On appelle le constructeur parent
self.a = liste_coeffs[2]
self.b = liste_coeffs[1]
self.c = liste_coeffs[0]
self.delta = self.b ** 2 - 4 * self.a * self.c
def racines(self) :
""" Calcule les racines éventuelles d'un trinome """
if self.delta < 0 :
return None
elif self.delta == 0 :
return -self.b / (2 * self.a)
else :
return ( (- self.b - sqrt(self.delta)) / (2 * self.a) ,
(- self.b + sqrt(self.delta)) / (2 * self.a) )
Testons maintenant notre nouvelle classe Trinome().
Cette classe ayant été explicitement définie comme fille de la classe Polynome(), elle a hérité de toutes les méthodes et de tous les attributs de celle-ci.
On peut donc exécuter le code suivant :
t1 = Trinome([2, -3, -5])
print(t1)
print("Delta=",t1.delta)
print("Racines",t1.racines())
print(t1.valeur(0.4))
Créer une classe pour représenter les nombre rationnels.
Vous définirez les méthodes permettant d’additionner, de soustraire, de multiplier et de diviser deux rationnels, ainsi qu'une méthode permettant un affichage sous la forme a/b.
# Votre classe ici
# Tester votre classe
p=Rationnel(2,3)
q=Rationnel(3,4)
print ("p=",p)
print ("q=",q)
print("p+q",p+q)
print("p-q",p-q)
print("p*q",p*q)
print("p/q",p/q)
Pour la gestion d'une bibliothèque, créer une classe Document() définissant une propriété booléen sorti, une propriété titre sous forme de chaîne de caractère, une méthode prete() et une méthode retourne() qui changent la valeur de la propriété sorti.
Créer ensuite une classe fille Livre() qui possédera en plus une propriété auteur et une propriété nombre_de_pages ainsi qu'une classe fille Dvd() avec une propriété duree en minutes.
Attention, toutes les propriétés doivent être initialisées par la méthode constructeur de la classe !
# Votre classe ici