La programmation orientée objet (POO) en Python
Généralités
En Python, la plupart des variables qu’on manipule sont des objets.
Dans la vie courante, un objet est “quelque chose” qui a :
-
une identité
-
des caractéristiques
-
un comportement
Exemple : Ma voiture possède :
-
un identifiant → son n° d’immatriculation
-
un comportement → un ensemble d’actions réalisables. Ex. : démarrer, rouler, klaxonner …
-
des caractéristiques → sa marque, sa cylindrée, sa couleur qui sont des caractéristiques qui ne changent pas dans le temps.
Mais aussi le nombre de litres de carburant dans le réservoir, le kilométrage qui sont également des caractéristiques mais qui évoluent dans le temps.
En Python, c’est pareil !
>>> # On définit un nombre complexe dont l'identifiant est 'z'
>>> z = 1 + 2j
>>> # On affiche les caractéristiques de 'z' à savoir sa partie réeelle et sa partie imaginaire
>>> z.real
1.0
>>> z.imag
2.0
>>> # On déclenche une action sur 'z' qui consiste à lui faire calculer son conjugé
>>> z.conjugate() (1)
(1-2j)
En Python, on appelle attribut une caractéristique d’un objet.
Une action est, quant à elle, appelée méthode.
On parle également de classe pour faire référence au type Python qui servira de modèle pour construire — on dit aussi instancier — autant d’objets que nécessaire.
>>> type(complex)
<#class# 'type'>
Parmi les attributs, on en distingue 2 types :
-
les attributs de classe → ce sont des attributs qui sont partagés par tous les objets de la classe ⇒ la modification d’un de ces attributs sera répercutée dans l’ensemble des objets construits à partir de cette classe
-
les attributs d’instance → ce sont des attributs propres à chacun des objets ⇒ ils peuvent donc avoir des valeurs différentes selon l’objet
La librairie Python standard propose déjà un nombre important de classes (c’est-à-dire de types) pré-définies. Cependant, il est tout à fait possible — et même recommandé — d’en définir de nouvelles pour s’adapter à nos besoins de traitement.
Une 1ère classe
Ci-dessous figure le code d’un script Python qui définit et fait appel à une classe Fraction
qui va permettre de manipuler des fractions mathématiques.
import math
# Définition de la classe
class Fraction :
# Déclaration d'attributs d'instance
nName = "numérateur"
dName = "dénominateur"
# Méthode spéciale Python prédéfinie qui est appelée automatiquement lors
# de la création d'un objet du type de cette classe
def __init__(self, num, den) :
# Déclaration et initialisation d'attributs d'instance : 'n' et 'd'
self.n = num
self.d = den
# Méthode utilisateur qui renvoie la valeur de l'attribut d'instance 'n'
def getNum(self) :
return self.n
# Méthode utilisateur qui renvoie la valeur de l'attribut d'instance 'd'
def getDen(self) :
return self.d
# Méthode utilisateur qui redéfinit la valeur des 2 attributs d'instance 'n' et 'd'
def setFrac(self, num, den) :
self.n = num
self.d = den
# Méthode spéciale Python correspondant à l'opérateur '+'
def __add__(self, other) :
# On calcule les numérateur et dénominateur de la somme des fractions
# après les avoir mises sur le même dénominateur
nSum = self.n * other.d + other.n * self.d
dSum = self.d * other.d
# On cherche le plus commun diviseur
pgcd = math.gcd(nSum, dSum)
# On simlifie le numérateur et dénominateur du résultat
nSum /= pgcd
dSum /= pgcd
# On retourne la somme sous la forme d'un nouvel objet Fraction
return Fraction(nSum, dSum)
# Méthode spéciale Python qui est appelée par la fonction 'print()'
def __repr__(self) :
return f"{int(self.n)}/{int(self.d)}"
if __name__ == "__main__":
# On instancie 2 fois la classe Fraction
f1 = Fraction(3,4)
f2 = Fraction(1,2)
# On affiche le détail des fractions à partir de la valeur de ses attributs
# de classe et d'instance
print(f"f1 -> {f1.nName} / {f1.dName} = {f1.getNum()} / {f1.getDen()}")
print(f"f2 -> {f2.nName} / {f2.dName} = {f2.getNum()} / {f2.getDen()}")
# On change la valeur des attributs de classe
# => La modification se répercute dans 'f1' et 'f2'
Fraction.nName = "numerator"
Fraction.dName = "denominator"
# On affiche le détail des fractions à partir de la valeur de ses attributs
# de classe et d'instance pour vérifier la bonne prise en compte de la valeur
# des attributs de classe
print(f"f1 -> {f1.nName} / {f1.dName} = {f1.getNum()} / {f1.getDen()}")
print(f"f2 -> {f2.nName} / {f2.dName} = {f2.getNum()} / {f2.getDen()}")
# On calcule la somme de 'f1' et 'f2' (<- appel à la méthode '__add__()' de 'Fraction')
f = f1 + f2
# On affiche le résultat via l'appel à la méthode '__repr__()' de 'Fraction'
print(f"{f1} + {f2} = {f}")
f1 -> numérateur / dénominateur = 3 / 4
f2 -> numérateur / dénominateur = 1 / 2
f1 -> numerator / denominator = 3 / 4
f2 -> numerator / denominator = 1 / 2
3/4 + 1/2 = 5/4
Le mot clé
self Le premier argument d’une méthode est toujours le mot clé
le sens de ce code est le suivant :
|
🞄 🞄 🞄