La programmation orientée objet (POO) permet de créer des entités (objets) que l'on peut manipuler et faire évoluer.
La structure et les méthodes d'un objet sont définis dans une classe.
Pour obtenir un objet il faut instancier une classe : on obtient alors un objet en mémoire appelé instance.
L'opération consistant à créer un objet à partir d'une classe est appelée instanciation.
Création d'une classe de base |
Commençons par créer une classe Perso contenant des renseignements simples sur des personnes. La classe Perso attends 3 paramètres :
class Perso:
""" La classe Perso attend 3 paramètres :
nom, prénom, et la date de naissance (optionnelle)
Exemple d'instanciation : perso1=Perso("Dupont","Pierre","25/12/2000")"""
def __init__(self,n,p,d_n=None):
self.nom=n
self.prenom=p
self.date_naissance=d_n
__init__ est une méthode particulière appelé constructeur : il s'agit de la méthode qui sera appelée lorsque la classe sera instanciée pour créer un nouvel objet.
Instancions quelques objets à partir de cette classe Perso :
perso1=Perso("PARADI","Hector","02/11/2000")
perso2=Perso("MOREAU","Valentine","27/08/2007")
perso3=Perso("RIVOLI","Gaspard")
Nous disposons maintenant de 3 objets, représentant chacun une personne : il s'agit de 3 instances de la classe Perso :
Appelons ces objets directement dans la console de Python et voyons les renseignements qu'il contiennent ou qu'ils nous renvoient. Demandons la valeur des 3 attributs de l'objet perso1 :
>>> perso1.nom
'PARADI'
>>> perso1.prenom
'Hector'
>>> perso1.date_naissance
'02/11/2000'
Dans la console de Python la fonction help permet d'obtenir des renseignement sur n'importe quelle fonction ou objet de Python. Demandons à la fonction help des information sur l'objet perso1 :
>>> help(perso1)
Help on Perso in module __main__ object:
class Perso(builtins.object)
| La classe Perso attend 3 paramètres : nom, prénom, et la date de naissance (optionnelle)
| Exemple d'instanciation : perso1=Perso("Dupont","Pierre","25/12/2000")
|
| Methods defined here:
|
| __init__(self, n, p, d_n=None)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
La fonction help nous affiche alors la documentation de l'objet que nous avons écrite en commentaire au début de la classe Perso. Elle affiche également la liste des méthodes et des attributs de l'objet :
Appelons cet attribut caché __dict__ :
>>> perso1.__dict__
{'date_naissance': '02/11/2000', 'nom': 'PARADI', 'prenom': 'Hector'}
Il nous renvoie un dictionnaire très clair, dans lequel les clés sont les attributs de l'objet et les valeurs sont leur valeur.
En réalité la syntaxe pointée perso.nom est un raccourcis vers perso1.__dict__["nom"] :
>>> perso1.__dict__["nom"]
'PARADI'
>>> perso1.nom
'PARADI'
Conclusion : à l'intérieur d'un objets les attributs sont mémorisé dans un dictionnaire. Ce dictionnaire est parfaitement accessible par perso1.__dict__
Si on modifie la valeur d'un attribut le dictionnaire est mis à jour :
>>> perso1.nom="MARTIN"
>>> perso1.nom
'MARTIN'
>>> perso1.__dict__
{'date_naissance': '02/11/2000', 'nom': 'MARTIN', 'prenom': 'Hector'}
Remarque : __dict__ est un attribut de l'objet perso1 donc on l'appelle directement sans parenthèse
Enfin on peut modifier un attribut en agissant durectement sur le dictionnaire __dict__ :
>>> perso1.__dict__["nom"]="PETIT"
>>> perso1.nom
'PETIT'
>>> perso1.__dict__
{'date_naissance': '02/11/2000', 'nom': 'PETIT', 'prenom': 'Hector'}
D'autres attributs cachés existent, comme __doc__ qui nous renvoie la documentation de la classe (commentaire que nous avons écrit en claiir au début de la classe Perso) :
>>> perso1.__doc__
' La classe Perso attend 3 paramètres :\n nom, prénom, et la date de naissance (optionnelle)\n Exemple d\'instanciation : perso1=Perso("Dupont","Pierre","25/12/2000")'
perso1.__doc__ renvoie une chaîne de caractère "brute" : le retour à la ligne y est codé par \n
Pour un affichage formaté il vaut mieux l'appeller avec print qui se chargera de l'affichage :
>>> print(perso1.__doc__)
La classe Perso attend 3 paramètres :
nom, prénom, et la date de naissance (optionnelle)
Exemple d'instanciation : perso1=Perso("Dupont","Pierre","25/12/2000")
Remarque : __doc__ est un attribut de l'objet perso1 donc on l'appelle directement sans parenthèse
D'autres méthodes cachées existent, comme __sizeof__ qui nous renvoie la place occupée en mémoire par l'objet (en octets) :
>>> perso1.__sizeof__()
16
Remarque : __sizeof__ est une méthode de l'objet perso1 donc on l'appelle avec des parenthèses
Que se passe-t-il si on appelle directement l'objet dans la console de Pyhton ou si on essaye de l'afficher avec la fonction print ?
>>> perso1
<__main__.Perso object at 0x0135CF10>
>>> print(perso1)
<__main__.Perso object at 0x0135CF10>
Pour l'instant rien de précis, à part que les informations affichées nous confirme que perso1 est une instance de la classe Perso.
En réalité si on appelle l'objet directement dans la console il exécute sa méthode spéciale __repr__ qui doit alors retourner une valeur ou un message. Or cette méthode spéciale __repr__ n'existe pas encore dans notre classe Perso. Ajoutons une nouvelle méthode spéciale __repr__ à notre classe Perso :
class Perso:
""" La classe Perso attend 3 paramètres :
nom, prénom, et la date de naissance (optionnelle)
Exemple d'instanciation : perso1=Perso("Dupont","Pierre","25/12/2000")"""
def __init__(self,n,p,d_n=None):
self.nom=n
self.prenom=p
self.date_naissance=d_n
def __repr__(self):
return "Vous avez lancé l'objet directement dans la console !"
Maintenant si on appelle directement l'objet perso1 dans la console (ou dans un programme) il retourne la valeur renvoyée par la méthode __repr__ :
>>> perso1
Vous avez lancé l'objet directement dans la console !
Et si on l'affiche avec print ?
>>> print(perso1)
Vous avez lancé l'objet directement dans la console !
Il renvoie pour l'instant le même message. Pour distinguer un appel direct de l'objet et un affichage propre avec la fonction print de Python nous allons ajouté une nouvelle méthode spéciale à notre classe appelée __str__. Cette méthode spéciale __str__ sera appelée lorsqu'on tente d'afficher l'objet avec print :
class Perso:
""" La classe Perso attend 3 paramètres :
nom, prénom, et la date de naissance (optionnelle)
Exemple d'instanciation : perso1=Perso("Dupont","Pierre","25/12/2000")"""
def __init__(self,n,p,d_n=None):
self.nom=n
self.prenom=p
self.date_naissance=d_n
def __repr__(self):
return "Vous avez lancé l'objet directement dans la console !"
def __str__(self):
return "Vous avez demandé un affichage de l'objet par print"
Maintenant l'appel direct ou l'affichage avec print ne renvoient pas le même message :
>>> print(perso1)
Vous avez demandé un affichage de l'objet par print
>>> perso1
Vous avez lancé l'objet directement dans la console !
Enfin ajoutons 2 méthodes à la classe Perso :
class Perso:
""" La classe Perso attend 3 paramètres :
nom, prénom, et la date de naissance (optionnelle)
Exemple d'instanciation : perso1=Perso("Dupont","Pierre","25/12/2000")"""
def __init__(self,n,p,d_n=None):
self.nom=n
self.prenom=p
self.date_naissance=d_n
def __repr__(self):
return "Vous avez lancé l'objet directement dans la console !"
def __str__(self):
return "Vous avez demandé un affichage de l'objet par print"
def age(self):
return 2025-int(self.date_naissance[-4:])
def info(self):
print("Voici toutes les informations disponibles :")
print("Nom : ",self.nom)
print("Prénom : ",self.prenom)
print("Date de naissance : ",self.date_naissance)
print("Age : %d ans" % self.age())
Et voilà ce qu'affichent ces deux nouvelles méthodes :
>>> perso1.age()
25
>>> perso1.info()
Voici toutes les informations disponibles :
Nom : PARADI
Prénom : Hector
Date de naissance : 02/11/2000
Age : 25 ans
Problème : pour l'instance perso3 nous n'avons pas précisé la date de naissance à sa création :
perso3=Perso("RIVOLI","Gaspard")
Donc si on demande d'afficher ses informations nous obtenons naturellement une erreur puisque la date de naissance vaut None et que l'age ne peut pas être calculé :
>>> perso3.info()
Voici toutes les informations disponibles :
Nom : RIVOLI
Prénom : Gaspard
Date de naissance : None
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "C:\site\fractale\nsi\activites\objets\objets.pyw", line 33, in info
print("Age : %d ans" % self.age())
File "C:\site\fractale\nsi\activites\objets\objets.pyw", line 26, in age
return 2025-int(self.date_naissance[-4:])
TypeError: 'NoneType' object is not subscriptable
Pour éviter cette erreur modifions notre classe perso afin de ne calculer et d'afficher l'age que si la date de naissance a été précisée :
class Perso:
""" La classe Perso attend 3 paramètres :
nom, prénom, et la date de naissance (optionnelle)
Exemple d'instanciation : perso1=Perso("Dupont","Pierre","25/12/2000")"""
def __init__(self,n,p,d_n=None):
self.nom=n
self.prenom=p
self.date_naissance=d_n
def __repr__(self):
return "Vous avez lancé l'objet directement dans la console !"
def __str__(self):
return "Vous avez demandé un affichage de l'objet par print"
def age(self):
return 2025-int(self.date_naissance[-4:])
def info(self):
print("Voici toutes les informations disponibles :")
print("Nom : ",self.nom)
print("Prénom : ",self.prenom)
if self.date_naissance==None:
print("Date de naissance non précisée")
else:
print("Date de naissance : ",self.date_naissance)
print("Age : %d ans" % self.age())
Ainsi nous n'obtenons plus d'erreur à l'affichage des informations de l'objet perso3 :
>>> perso3.info()
Voici toutes les informations disponibles :
Nom : RIVOLI
Prénom : Gaspard
Date de naissance non précisée
Voici le code source en Python de la version finale de cette classe Perso :
![]() |
Autre exemple de POO en utilisant cette fois la Tortue de Pyhton. Le programme suivant implémente une classe pion pour dessiner un pion dans la fenêtre de la torue.
Cette classe dispose de 3 attributs :
Elle possède également 3 méthodes permettant de "piloter" le pion :
Enfin elle permet de créer autant de pion que l'on veut, il suffit d'instancier chacun d'entre eux. Par exemple, si on crée 10 instances de la classe pion on dispose de 10 pions indépendants dans la fenêtre de la tortue, chacun possédant ses propres attributs et ses propres méthodes.
![]() |
L'héritage |
Créons une nouvelle classe Chaine pour créer des objets de type chaîne de caractères :
class Chaine:
""" La classe Chaine attend 1 paramètre : la valeur de la chaîne
Exemple d'instanciation : ch1=Chaine("Bonjour")"""
def __init__(self,ch):
self.chaine=ch
def __repr__(self):
return self.chaine
def __str__(self):
return self.chaine
Instancions quelques objets à partir de cette classe Chaine puis affichons leur contenu :
>>> ch1=Chaine("Bonjour")
>>> ch2=Chaine("le soleil brille")
>>> ch3=Chaine("La POO en Python c'est super !")
>>> ch1.chaine
'Bonjour'
>>> ch2
le soleil brille
>>> print(ch3)
La POO en Python c'est super !
Jusque là rien de particulier : notre classe Chaine possède un seul attribut chaine qui contient la valeur de la chaîne de caractère mémorisée dans l'objet.
Ajoutons 2 méthodes à notre classe Chaine :
class Chaine:
""" La classe Chaine attend 1 paramètre : la valeur de la chaîne
Exemple d'instanciation : ch1=Chaine("Bonjour")"""
def __init__(self,ch):
self.chaine=ch
def __repr__(self):
return self.chaine
def __str__(self):
return self.chaine
def premier(self):
return self.chaine[0]
def dernier(self):
return self.chaine[-1]
Testons ces deux nouvelles méthodes :
>>> ch1=Chaine("Bonjour")
>>> ch1.premier()
'B'
>>> ch1.dernier()
'r'
En utilisant la notation pointée dans la console de Python on retrouve bien l'attribut chaine et les 2 méthodes premier et dernier de notre classe dans l'auto-complétion :
Notre classe Chaine dispose de 2 nouvelles méthodes premier et dernier qui n'existait pas dans la classe de base str de Python. Or, la classe str de Python permettant de créer des objets de type chaîne de caractères possédait un grand nombre de méthodes bien pratiques (upper, join, split, count, find, etc.).
Il serait bien pratique que notre classe Chaine possède toutes les méthodes de la classe str, en plus de nos nouvelles méthodes.
Et bien le paradigme de l'héritage en POO sert justement à celà : lorsqu'on créer une nouvelle classe, elle peut hériter de l'ensemble des méthodes d'une classe déjà existante.
Pour cela, il suffit de placer en paramètre (entre parenthèse) le nom de la classe mère dans la déclaration de la classe fille :
class Chaine(str):
""" La classe Chaine attend 1 paramètre : la valeur de la chaîne
Exemple d'instanciation : ch1=Chaine("Bonjour")"""
def __init__(self,ch):
self.chaine=ch
def __repr__(self):
return self.chaine
def __str__(self):
return self.chaine
def premier(self):
return self.chaine[0]
def dernier(self):
return self.chaine[-1]
Ainsi, un objets instancié par la classe Chaine possèdent toutes les méthodes de la classe str en plus des nouvelles méthodes premier et dernier que nous avons programmées. C'est comme si on avait ajouter des nouvelles méthodes à la classe str.
L'auto-complétion confirme la liste des méthodes utilisables avec l'objet ch2 :
Et voici quelques tests dans la console :
Voici le code source en Python de la version finale de cette classe Chaine qui hérite de la classe str :
![]() |
Conclusion |
L'intérêt des objets est de pouvoir les utiliser sans se préoccuper de la manière dont ils sont programmés en interne (comme on le fait lorsqu'on utilise une liste ou un dictionnaire qui sont des objets).
On sait désormais créer des classes personnelles permettant de fabriquer sur mesure des objets répondant à un problème précis (exemple : programmer un jeu).
De plus, une classe peut très bien hériter des méthodes d'une classe déjà existente sans qu'il soit nécessaire de tout reprogrammer.
Enfin, la programmation orienté objet (POO) permet d'obtenir un code source propre, concis et structuré.
Avec tout ça libre à vous d'utiliser naturellement et intensivement les objets pour tous vos projets futurs.
Réalisé par Jean-Christophe MICHEL
© Mars 2025