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 ! Exemple : >>> # 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. Exemple : >>> 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}") Résultat : 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é self. Cet argument dénote l’objet sur lequel on est en train de travailler. Ainsi, lorsqu’on écrit : def setFrac(self, num, den) : self.n = num self.d = den le sens de ce code est le suivant : on définit la méthode setFrac() de la classe qui aura 2 arguments (il ne faut pas compter self qui est un argument spécial) lorsque l’on appelle cette méthode avec une syntaxe du type f1.setFrac(4, 5), ceci a pour effet de modifier la valeur des attributs d’instance n et d de l’objet f1 c’est-à-dire celui sur lequel la méthode est appelée. 🞄 🞄 🞄 Liens Python NodeRED