Améliorer ses objets
Nous allons utiliser plusieurs techniques permettant de fluidifier l'usage des objets.
Ajout d'un paramètre dans le constructeur
On souhaite par pouvoir choisir le pas de notre compteur (c'est-à-dire ajouter 2 à chaque fois plutôt que 1 par exemple). Pour faire cela on va ajouter un paramètre dans le constructeur pour que chaque compteur puisse connaître son pas :
Fichier compteur.py
:
class Compteur:
def __init__(self, pas):
self.valeur = 0
self.pas = pas
# ...
Il faut alors changer le code pour construire les objets avec ce nouveau paramètre :
Fichier main.py
:
from compteur import Compteur
c1 = Compteur(3)
c2 = Compteur(1)
#...
Notez bien que le premier paramètre de la définition de la classe est TOUJOURS self. Le premier paramètre de l'utilisation de la méthode est alors le second dans sa définition.
Et il faut modifier la méthode incrémente(self)
pour qu'elle prenne en compte le pas :
class Compteur:
# ...
def incrémente(self):
self.valeur = self.valeur + self.pas
# ...
On définira toujours les différents attributs de l'objet dans le constructeur __init__
.
On le fera de cette façon :
self.nom_attribut = valeur_attribut
Cette façon de faire :
- attributs dans les objets
- méthodes (fonctions) dans les classes
permet à chaque objet (le paramètre self
) d'être différent tout en utilisant les mêmes méthodes.
Lors de l'utilisation d'une méthode, l'objet est passé en premier paramètre, ce qui permet de réutiliser tous ses attributs.
Paramètres par défaut
Le souci avec la méthode précédente, c'est que même si le pas est de 1
, il faut le définir dans la construction de l'objet. Nous allons changer ça en mettant un paramètre par défaut.
En python cela donne (fichier compteur.py
) :
class Compteur:
def __init__(self, pas=1):
self.valeur = 0
self.pas = pas
def incrémente(self):
self.valeur = self.valeur + self.pas
On peut utiliser deux fois le même nom pas
car ils sont dans des espaces de noms différents :
- un dans l'espace de noms de la fonction (créé lorsque l'on exécute la fonction et détruit à la fin. Attention : on détruit les noms pas les objets)
- un dans l'objet lui-même.
Le code final de main.py
pourra alors être :
from compteur import Compteur
c1 = Compteur(3)
c2 = Compteur()
c1.incrémente()
c2.incrémente()
c1.incrémente()
print(c2.valeur)
Valeur initiale
Finissons cette partie en ajoutant une valeur initiale à notre compteur :
Fichier compteur.py
:
class Compteur:
def __init__(self, pas=1, valeur=0):
self.valeur = valeur
self.pas = pas
def incrémente(self):
self.valeur = self.valeur + self.pas
On peut créer de compteur de plein de façon différente maintenant. Par exemple :
Compteur()
: créera un compteur devaleur=0
et depas=1
,Compteur(3)
: créera un compteur devaleur=0
et depas=3
,Compteur(3, 12)
: créera un compteur devaleur=12
et depas=3
,Compteur(pas=3)
: créera un compteur devaleur=0
et depas=3
,Compteur(valeur=12)
: créera un compteur devaleur=12
et depas=1
Méthodes spéciales
Python dispose de méthodes spéciales qui peuvent être invoquées en utilisant une syntaxe particulière. On a déjà vu __init__
, mais il y en a d'autres.
Elles sont rès pratiques car elles permettent d'utiliser nos objets de façon intuitive, comme si on utilisait des objets de python (affichage à l'écran, comparaison, exécution comme une fonction, ...).
Vous en trouverez une liste
exhaustive dans la documentation officielle. Nous allons
en utiliser ici quelques-unes sur notre classe. Ces méthodes se présentent toujours sous la forme __nom_de_la_méthode__
Représentation
Essayez de taper dans le fichier main.py
:
c = Compteur()
print(c)
Vous devriez obtenir quelque chose comme :
<__main__.Compteur object at 0x107149100>
La fonction print
appelle la méthode __str__
de notre classe. En effet, print
affiche à l'écran une chaîne de caractères. L'objet à afficher est donc converti en str
avant.
Comme nous n'avons pas défini cette méthode, c'est donc la méthode par défaut de tous les objets python qui est appelée. Comme vous le constatez, elle n'est pas très intéressante pour nous. Il faut donc la définir dans notre classe.
On va faire en sorte de pouvoir lire les valeur de notre objet sous la forme d'une chaîne de caractères :
class Compteur
# ...
def __str__(self):
return "Compteur(pas=" + str(self.pas) + ", valeur=" + str(self.valeur) + ")"
Avec cette nouvelle méthode, le code précédent donne :
Compteur(pas=1, valeur=0)
Ce qui est bien plus lisible.
Comparaison
Finissons en essayant de comparer deux compteurs :
c1 = Compteur(valeur=1)
c2 = Compteur(valeur=4)
print(c1 < c2)
Si on teste ça avec votre code tel qu'il est, on obtiendra :
TypeError: '<' not supported between instances of 'Compteur' and 'Compteur'
Python vous explique qu'il ne connaît pas l'opérateur <
pour les objets de notre classe. Pour pouvoir utiliser
directement les opérateurs <
et >
, il faut définir respectivement les méthodes __lt__(self, other)
(lower than) et
__gt__(self, other)
(greater than). On pourra aussi ajouter __eq__(self, other)
pour tester l'égalité.
Par exemple pour ajouter la comparaison strictement plus petit que, on ajoute la méthode :
class Compteur
# ...
def __lt__(self, other):
return self.valeur < other.valeur
# ...
On peut maintenant comparer 2 compteurs, ou un compteur à toute autre objet qui possède l'attribut valeur.
Ajoutez les comparaisons :
- strictement plus grand que
- égal
Au compteur.
Les différents opérateurs de comparaison que l'on peut ajouter à nos objets sont décrits dans la documentation.
Code
Les deux fichiers sont dans le même dossier compteur/
qui fait office de projet vscode.
Fichier compteur.py
:
class Compteur:
def __init__(self, pas=1, valeur=0):
self.valeur = valeur
self.pas = pas
def __str__(self):
return "Compteur(pas=" + str(self.pas) + ", valeur=" + str(self.valeur) + ")"
def __lt__(self, other):
return self.valeur < other.valeur
def __gt__(self, other):
return other.valeur < self.valeur
def __eq__(self, other):
return other.valeur == self.valeur
def incrémente(self):
self.valeur = self.valeur + self.pas
Fichier main.py
:
from compteur import Compteur
c1 = Compteur(3)
c2 = Compteur()
c1.incrémente()
c2.incrémente()
c1.incrémente()
print(c1.valeur, c1)
print(c2.valeur, c2)
print(c1 < c2)