Vous pouvez me contacter via Facebook pour questions & suggestions :
Page Facebook relative à mon site
La POO correspond à une autre manière d’imaginer, de construire et d’organiser son code.
Python est résolument orienté objet, tout est construit autour de la notion d'objet.
Avant de vous montrer comment créer vos propres classes en Python, il est utile de vous rappeler les principales classes prédéfinies proposées par Python.
# nom du programme : classes_natives.py
machaine = "bonjour"
print(machaine, " est un objet de ", type(machaine))
machaine2 =str()
print(machaine2, " est un objet de ", type(machaine2))
maliste = [1,2,3,4]
print(maliste, " est un objet de ", type(maliste))
maliste2 =list()
print(maliste2, " est un objet de ", type(maliste2))
monentier =9
print(monentier, " est un objet de ", type(monentier))
monentier2 =int()
print(monentier2, " est un objet de ", type(monentier2))
mondecimal =10.5
print(mondecimal, " est un objet de ", type(mondecimal))
mondecimal2 =float()
print(mondecimal2, " est un objet de ", type(mondecimal))
montuple =(5,4,3)
print(montuple, " est un objet de ", type(montuple))
montuple2 =tuple()
print(montuple2, " est un objet de ", type(montuple2))
mondict ={"manteaux" : 2, "vestes" : 3}
print(mondict, " est un objet de ", type(mondict))
mondict2 =dict()
print(mondict2, " est un objet de ", type(mondict2))
monset = {0,1,2,3,4,5}
print(monset, " est un objet de ", type(monset))
monset2 =set()
print(monset2, " est un objet de ", type(monset2))
Sauf créer des séries vides, vous n'êtes pas obligé d'utiliser un constructeur pour produire une instance de classe native.
Un objet de classe prédéfinie mais non vide peut être créé alors de façon littérale comme je le montre dans la
routine ci-dessus.
Par exemple les termes d'une liste sont délimités par des crochets, les termes
d'un tuple par des parenthèses, les termes d'un ensemble par des accolades, les paires clé:valeur d'un dictionnaire par des accolades, etc.
Vous êtes aussi obligé d'utiliser un constructeur pour produire une liste, un tuple, un ensemble à partir d'un objet range.
Dès que l'on a créé, par exemple, un objet de type 'list' on peut lui appliquer toutes les méthodes de cette classe.
Exemple : méthodes applicable à un objet str :
>>>dir(str) 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate',', 'upper', 'zfill'
Donc utilisez dir(nomClasse) / help(nomClasse) pour avoir la liste des méthodes de cette classe.
la commande dir() affiche simplement le nom des méthodes alors que help() donne le détail.
Si vous tapez la commande dir(list) toutes les méthodes s'affichent et d'abord les méthodes magiques dont la méthode __add()__.
>>> liste1 =[1,2,5] >>> liste2 =[3,4] >>> liste3 = liste1 + liste2 >>> liste3 [1, 2, 5, 3, 4] >>> str1 = "aeiou" >>> str2 ="bcdfgh" >>> str3 = str1 + str2 >>> str3 'aeioubcdfgh'
Lorque vous utiliser l'opérateur + entre deux listes, il y appel automatique de la méthode magique __add()__ afin de mettre bout à bout les éléments les éléments des deux listes.
La méthode magique __add()__ existe aussi pour la classe str. Si utilisation de l'opérateur + entre deux chaines il y a alors concaténation.
Dans la suite de ce chapitre je vais vous montrer comment créer vos propres classes et instances (ou objets).
Prenons un exemple tiré de la vie courante pour illustrer la POO.
Médor est un chien. Pendant une journée typique, il fait diverses actions: il mange, il court, il dort, etc.
De plus, Médor a diverses qualités ou attributs ou propriétés (taille, couleur de poil,etc).
En POO on utilise les termes suivants : classe, instance de classe (ou objet), attributs et méthodes de classe.
La relation entre un attribut OU une méthode et l’objet est indiquée par un point écrit entre les deux. C'est ce qu'on appelle la notation pointée.
Dans cette deuxième partie je vous montre comment créer vos propres classes et instances de classe.
Dans ce programme je définis une classe nommée Personne avec deux propriétés ; il n'y a pas de méthode sauf
la méthode __init() qui est obligatoire (c'est le constructeur).
Ensuite je crée deux instances de cette classe.
# nom programme : poo1.py
# définition classe Personne avec deux attributs
class Personne:
def __init__(self,n,a):
self.nom = n
self.age = a
# création d'une instance dans la classe Personne
p1 = Personne("Albert",27)
print(f"nom de p1 : {p1.nom} et âge de p1 {p1.age} ans")
# instanciation de Personne
p2 =Personne("Evelyne",47)
print(f"nom de p2 : {p2.nom} et âge de p2 : {p2.age} ans")
# modifier les attributs de objet p1
p1.age = 28
p1.nom ="Einstein"
print(f"nom et âge modifiés de p1 : {p1.nom} {p1.age} ans")
print(type(p1))
print(type(p2))
Dans le cadre de classes personnalisées, la première lettre du nom doit être en majuscule.
La méthode __init()) est la fonction de construction. Elle est automatiquement appelée lorsque l'on crée une instance de classe.
Notez que j'ai systématiquement utilisé des chaines formatées ("f string") pour les affichages et à l'intérieur de cette chaine formatée je pratique la notation pointée (objet.propriété).
nom de p1 : Albert et âge de p1 27 ans nom de p2 : Evelyne et âge de p2 : 47 ans nom et âge modifiés de p1 : Einstein 28 ans class '__main__.Personne'> class '__main__.Personne'>
Observez attentivement le rendu.
Les objets sont de type '__main__.Personne'.
Dans ce programme je définis une classe personnelle nommée Rectangle avec deux propriétés et deux méthodes.
#nom du programme : poo2.py
class Rectangle:
def __init__(self,L,l):
self.Longueur=L
self.Largeur=l
# méthodes de classe ci-dessous
def surface(self):
return self.Longueur*self.Largeur
def perimetre(self):
return (self.Longueur* 2) + (self.Largeur*2)
# création d'une instance de Rectangle
rect1 = Rectangle(7,5)
print("Caractéristiques de rect1" , end=" : ")
print(f"la surface est : \
{rect1.surface()} et le périmètre est : {rect1.perimetre()}")
# modifier les attributs de l'instance r1
rect1.Longueur = 9
rect1.largeur = 6
print (f"Nouveaux périmètre et surface de rect1 : \
{rect1.surface()} et {rect1.perimetre()}")
#création d'un objet Rectangle
rect2 = Rectangle(6,6)
print("Caractéristiques de rect2" , end=" : ")
print(f"la surface est : {rect2.surface()} et \
le périmètre est : {rect2.perimetre()}")
Dans ce programme je vous montre que dans le cadre de chaines formatées je peux mettre entre accolades des expressions complexes telles rect1.surface(), rect1.perimetre().
Caractéristiques de rect1 : la surface est : 35 et le périmètre est : 24 Nouveaux périmètre et surface de rect1 : 45 et 28 Caractéristiques de rect2 : la surface est : 36 et le périmètre est : 24
Dans les deux exemples précédents le programme est complexifié par les instructions d'affichage.
Il est donc important que dans la définition de la classe il y ait une méthode qui permet de présenter
de façon détaillée une instance de classe.
# nom programme : poo3.py
class Voiture:
def __init__(self, pr, ma, mo):
self.proprio = pr
self.marque = ma
self.modele = mo
def presenter(self):
print(f" {self.proprio} possède une : {self.marque} - {self.modele} ")
# Création d'instances de la classe Voiture :
julien = Voiture("Julien", "Peugeot", "2008 série 2")
louis = Voiture("Louis","Renault","clio5")
# Appel de la méthode presenter() :
julien.presenter()
louis.presenter()
Notez dans la définition de la classe la méthode presenter() qui affiche toutes les propriétés pour l'objet ciblé.
Donc pour afficher les attributs d'un objet il suffit d'écrire tout simplement : NomObjet.presenter()
Julien possède une : Peugeot - 2008 série 2 Louis possède une : Renault - clio5
Maintenant que vous avez observé attentivement le code de ces trois programmes, on peut expliquer la syntaxe Python que nous avons utilisé.
Syntaxe : class Nomclasse:
Par convention le nom d’une classe commence toujours par une majuscule.
Dans le même bloc il faut définir les attributs et méthodes de la classe.
Il faut obligatoirement un constructeur basé sur la méthode magique __init__() pour définir les propriétés :
def __init__(self,param1, param2, ...):
self.variable1=param1
self.variable2=param2
...
Le mot "self" est obligatoire.
def méthode(self):
return expression / print (expression)
Une méthode peut retourner une expression ou afficher cette expression.
Syntaxe : nomObjet = NomClasse(propriété1, propriété2, etc. )
Syntaxe : nomObjet.propriété = nouvelle valeur
Syntaxe : nomObjet.méthode()
Le mot-clé self en Python est un élément fondamental de la programmation orientée objet (POO).
Il représente l'instance actuelle de la classe, c'est-à-dire l'objet lui-même.
Si la méthode __init__() comprend trois paramètres (dont self), il faut alors passer deux arguments pour créer une
nouvelle instance de classe.
L'héritage est un concept fondamental de la programmation orientée objet. Il permet de créer de nouvelles classes basées sur des classes existantes, facilitant ainsi la réutilisation et l'extension du code.
# nom programme : heritage.py
#création d'une classe Personne
class Personne:
def __init__(self,nom,age):
self.nom = nom
self.age=age
# La classe Etudiant hérite de la classe Personne
class Etudiant(Personne):
def __init__(self,nom,age,filiere):
super().__init__(nom, age)
self.filiere = filiere
def presenter(self):
print(f"{self.nom} est âgé de {self.age} \
et est inscrit en {self.filiere}")
# Créer des instances de Personne
personne1 = Personne('Dupuis',60)
personne2 = Personne('Durand',40)
# présenter les instances de Personnne :
print(personne1.nom, ' est âgé de ' , personne1.age)
print(personne2.nom, ' est âgé de ' , personne2.age)
#créer des instances de Etudiant
etudiant1 = Etudiant("Alain",27,"math")
etudiant2 = Etudiant("Isabelle",21,"informatique")
# présenter les instances de Etudiant :
etudiant1.presenter()
Attention la syntaxe devient un peu plus compliquée ...
Dupuis est âgé de 60 Durand est âgé de 40 Alain est âgé de 27 et est inscrit en math Isabelle est âgé de 21 et est inscrit en informatique
Le polymorphisme en programmation orientée objet (POO) permet à une classe enfant de redéfinir les méthodes héritées de la classe mère, offrant ainsi un comportement différent tout en conservant la même interface.
# polymorphisme.py
class Primate:
def communiquer(self):
return"pousse des cris stridents."
class Singe(Primate):
def communiquer(self):
return "fait des gestes et crie"
class Humain(Primate):
def communiquer(self):
return "parle voire vocifère, écrit parfois"
Jojo =Primate()
Kong =Singe()
Trump = Humain()
print('Jojo ', Jojo.communiquer())
print('Kong ', Kong.communiquer())
print('Trump ', Trump.communiquer())
Ici toutes les classes implémentent la méthode "communiquer()".
Jojo pousse des cris stridents. Kong fait des gestes et crie Trump parle voire vocifère, écrit parfois
Le rendu de la méthode communiquer() diffère en fonction de l'origine de l'instance.
L'encapsulation permet de protéger les données internes d'une classe contre les accès non autorisés.
Les propriétés d'un objet doivent devenir privées ; on ne peut plus les modifier via la notation pointée.
On ne peut modifier les propriétés qu'au travers de méthodes publiques comprenant des dispositifs de contrôle.
#encapsulation.py
class Compte:
def __init__(self, nom,solde):
self.__nom = nom.strip()
self.__solde = int(solde)
def deposer(self, montant):
self.__solde += int(montant)
def retirer(self,montant):
self.__solde -= int(montant)
def detail(self):
return f"{self.__nom} a un solde de : {self.__solde}"
# Utilisation
dupuis = Compte(" Dupuis Jean ","5000")
print(dupuis.detail())
dupuis.deposer("500")
print(dupuis.detail())
dupuis.retirer("200")
print(dupuis.detail())
dupuis.nom ="Durand Paul"
print(dupuis.detail())
dupuis.solde =10000
print(dupuis.detail())
martial = Compte(" Martial Paul","3000")
print(martial.detail())
self.__nom = nom.strip() : la propriété __nom est privée car son nom commence par deux _
self.__solde = int(solde) : la propriété __solde est privée car son nom commence par deux _
Lors de l'instanciation le premier argument saisi sera débarassée des espaces inutiles et la chaine au format numérique
sera convertie en un entier.
Dupuis Jean a un solde de : 5000 Dupuis Jean a un solde de : 5500 Dupuis Jean a un solde de : 5300 Dupuis Jean a un solde de : 5300 Dupuis Jean a un solde de : 5300 Martial Paul a un solde de : 3000
Les tentatives de modifications des propriétés de l'objet "dupuis" via la notation pointée ont échoué mais sans 'plantage' du
programme ; les instructions sont tout simplement ignorées.
On ne peut modifier le solde d'un compte qu'au travers des méthodes deposer() & retirer().
Ensuite je crée une deuxième instance de la classe Compte.
Dans le cadre de la POO on peut utiliser les méthodes spéciales dites aussi méthodes magiques.
Ellles sont appelées parfois méthodes "double underscore" car elles sont précédées et suivies toujours par deux undersocres.
La plus connue des méthodes magiques est __init()__ ; elle est incontournable et est utilisée pour définir les propriétés.
Elle est appelée automatiquement lorsque l'on crée une instance de classe.
Nous allons employer la méthode magique __str__()
# nom programme : magique.py
class Rectangle:
def __init__(self, ha,la,u):
self.hauteur = ha
self.largeur = la
self.unite = u
def __str__(self):
return f"Rectangle de hauteur {self.hauteur} /
{self.unite} et de largeur {self.largeur} {self.unite} "
rectangle1= Rectangle(50,30,'cm')
rectangle2= Rectangle(30,50,'cm')
print(rectangle1)
print(rectangle2)
La méthode magique __str__(self) est utilisée pour créer une chaine formatée.
Comme par magie, cette méthode est appelée avec l'instruction print(instanceDeClasse)
Rectangle de hauteur 50 cm et de largeur 30 cm Rectangle de hauteur 30 cm et de largeur 50 cm
Il existe d'autres méthodes magiques dont la méthode __add__() évoquée en début de chapitre.