Accueil

Traduction

Tutoriel Python - sommaire

Tutoriel Python - recherche

L'auteur : Patrick Darcheville

Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site

Programmation objet en Python

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.

Classes natives et instances de ces classes

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.

Le programme

# 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.

Le rendu

Les méthodes des classes natives

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.

Mais quels sont les méthodes de liste ?

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'

Aide-mémoire

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.

Méthodes magiques prédéfinies

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()__.

Rôle de la méthode magique __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.

La terminologie et syntaxe de la POO

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.

La syntaxe

De plus, Médor a diverses qualités ou attributs ou propriétés (taille, couleur de poil,etc).

Terminologie

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.

Créer ses propres classes et instances

Dans cette deuxième partie je vous montre comment créer vos propres classes et instances de classe.

Exemple basique

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.

Le code

# 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é).

Le rendu

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'.

Une classe qui définit deux propriétés et deux méthodes

Dans ce programme je définis une classe personnelle nommée Rectangle avec deux propriétés et deux méthodes.

Le code

#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().

Le rendu

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

Une méthode pour décrire chaque instance de la classe

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.

Le code

# 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()

Le rendu

Julien possède une : Peugeot - 2008 série 2 
Louis possède une : Renault - clio5 

Syntaxe Python et POO

Maintenant que vous avez observé attentivement le code de ces trois programmes, on peut expliquer la syntaxe Python que nous avons utilisé.

Définir une classe

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.

Définir les attributs de 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.

Définir une méthode

def méthode(self):         
        return expression / print (expression)

Une méthode peut retourner une expression ou afficher cette expression.

Créer une instance de classe / un objet de classe

Syntaxe : nomObjet = NomClasse(propriété1, propriété2, etc. )

Modifier une propriété d'un objet

Syntaxe : nomObjet.propriété = nouvelle valeur

Appliquer une méthode à un objet

Syntaxe : nomObjet.méthode()

Le mot self

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.

Héritage

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.

Programme avec héritage

Le 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 ...

Le rendu

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

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.

Exemple : le code

# 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()".

Le rendu

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

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.

Exemple : le code

#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.

Le rendu

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.

Les méthodes magiques (ou spéciales)

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.

Programme avec une méthode magique

Nous allons employer la méthode magique __str__()

Le code

# 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)

Le rendu

Rectangle de hauteur 50 cm et de largeur 30 cm 
Rectangle de hauteur 30 cm et de largeur 50 cm 

Remarque

Il existe d'autres méthodes magiques dont la méthode __add__() évoquée en début de chapitre.