TNSI : cours POO - Programmation Orienté Objet (OOP)⚓︎
Introduction⚓︎
La POO est une nouvelle (pour nous cette année) méthode de programmation, on parle de nouveau paradigme de programmation, basé autour du concept central d'Objet.
Intuitivement, un
- de quoi parle-t-on? (de quel objet matériel)
- de qui parle-t-on? (de quel objet vivant)
- de quel concept/objet intelectuel abstrait parle-t-on?
On pourra par la suite définir plus précisément ce que l'on peut en faire.
Définitions⚓︎
Objets⚓︎
Le concept d'
- une matérialisation spécifique unique d'un objet matériel
- une incarnation spécifique unique d'une forme de vie
- une instance spécifique unique d'un concept intelectuel et/ou abstrait
Un Objet au sens de la POO, peut modéliser respectivement :
- Un objet matériel précis :
- La voiture de mon cousin Laurent, peut être vue comme un Objet (au sens de la POO).
- Le vélo bleu de ma fille
- Un être vivant précis :
- Mon cousin Julien, peut être considéré comme un Objet (au sens POO)
- mon chat nommé Mishka
- Un exemplaire/une instance précis(e) d'un concept intelectuel et/ou abstrait :
- Mon compte Bancaire personnel, sur le site de ma banque, peut être vu comme un Objet (au sens POO)
- Le tableau de mes notes de Maths au T1 de cette année
Le graphe modélisant les maisons et les rues de ma résidence
Classes et Instances⚓︎
- Par opposition à un Objet précis, une
Classe est une modélisation abstraite d'un ensemble d'Objets de même Catégorie, disposant de certaines caractéristiques communes. - De manière plus appliquée, une Classe peut être vue/utilisée comme une sorte de moule/usine à fabriquer des Objets, appelés des
instances de la Classe: - Au lieu de dire qu'on fabrique un objet d'une certaine Classe/Catégorie, on préfère dire que: on obtient un Objet en instanciant la Classe (/la Classe a été instanciée)
- l'Objet ainsi créé est une
instance de la Classe
Une Classe, au sens de la POO, est un moule/usine à fabriquer des Objets de types/genre divers :
- des Objets matériels :
- La Classe Voiture modélise le concept général de Voiture.
- La Classe Voiture est une usine à fabriquer des Objets voitures: on instancie la Classe Voiture pour fabriquer un Objet voiture.
- L'Objet "voiture de mon cousin Laurent" est une instance de la Classe Voiture.
- L'Objet "voiture de mon amie Julie" est une autre instance de la Classe Voiture.
-
La Classe Velo modélise le concept général de Vélo.
- La Classe Velo est une usine à fabriquer des Objets vélo: on instancie la Classe Velo pour fabriquer un Objet vélo.
- L'Objet "vélo de ma fille" est une instance de la Classe Velo.
- L'Objet "vélo de Farid" est une autre instance de la Classe Velo.
-
des Objets modélisant des Êtres vivants :
- La Classe Personne modélise le concept général de Personne.
- L'Objet "Sophie" est une instance de la Classe Personne.
- L'Objet "Paul" est une autre instance de la Classe Personne.
- La Classe Chat modélise le concept général de Chat.
- L'Objet "mon chat Mishka" est une instance de la Classe Chat.
- L'Objet "Le Chat de ma voisine Laura" est une autre instance de la Classe Chat.
- des Objets modélisant un concept intelectuel et/ou abstrait :
- La Classe Compte (Bancaire) modélise le concept général de compte bancaire.
- L'Objet "Mon compte Bancaire personnel" est une instance de la Classe Compte
- L'Objet "Ton compte Bancaire personnel" est une autre instance de la Classe Compte
-
La Classe Tableau modélise le concept général de Tableau.
- L'Objet "Tableau de mes notes de Maths au T1 cette année" est une instance de la Classe Tableau
- L'Objet "Tableau des Témpératures quotidiennes à 12h, à mon adresse, en Octobre" est une autre instance de la Classe Tableau
-
La Classe Graphe modélise le concept général de Graphe (réunion de Sommets dont certains sont reliés entre eux par des Arcs).
- L'Objet "Le graphe modélisant les maisons et les rues de ma résidence" est une instance de la Classe Graphe
- L'Objet "Le graphe modélisant les connexions filaires de mon réseau LAN" est une autre instance de la Classe Graphe
Attributs & Méthodes⚓︎
Attributs & Méthodes⚓︎
Une
-
des
attributs ouchamps : ce sont des caractéristiques statiques, descriptives :- de l'état d'un objet, et/ou
- de ses liens avec le monde extérieur (de la Classe)
En pratique, les attributs sont des variables
-
des
méthodes : ce sont des caractéristiques dynamiques, d'(inter)actions/opérations possibles par/avec cet objet. En pratique, ce sont des fonctions.
- Les attributs que nous considérerons sont (à priori) distinctes pour chaque Objet distinct: ce sont donc des variables qui dépendent de chaque instance (distincte). C'est ce qu'on appelle des
variables d'instance . En pratique pour nous, dans toute la suite, les Attributs seront des variables d'instances. - CULTURE : Pour information, il est possible de définir des attributs qui prennent obligatoirement la même valeur pour TOUTES les instances de la classe (pour tous les objets distincts), et sont donc indépendantes des instances, mais dépendent exclusivement de la Classe: on les appelle des
variables de classe . Nous ne les utiliserons pas.
Signature d'une méthode⚓︎
La
- du nom de ses paramètres
- des types de données des paramètres en entrée
- du type de données de la valeur de retour/sortie (quel type de données renvoie le
return
?)
Exemples⚓︎
Quelques exemples possibles d'Attributs et Méthodes disponibles pour les (Objets des) Classes suivantes :
Classes d' Objets matériels :
-
Classe Voiture :
-
Attributs pour un objet de Classe Voiture :
- la variable stockant sa
marque
- la variable stockant son
modèle
- la variable stockant son
poids
- la variable stockant son
annee_de_mise_en_circulation
- la variable stockant sa
couleur
- la variable stockant sa
nombre_de_portes
- la variable stockant sa
-
Méthodes pour un objet de Classe Voiture :
- la fonction
depasser()
- la fonction
klaxonner()
- la fonction
se_garer()
- la fonction
gonfler_pneus()
- la fonction
-
-
Classe Velo :
-
Attributs pour un objet de Classe Velo :
- la variable stockant sa
marque
- la variable stockant son
modèle
- la variable stockant son
poids
- la variable stockant son
annee_fabrication
- la variable stockant sa
couleur
- la variable stockant si OUI ou NON il dispose d'une
bequille
- la variable stockant sa
-
Méthodes pour un objet de Classe Velo :
- la fonction
depasser()
- la fonction
klaxonner()
- la fonction
attacher_cadenas()
- la fonction
remettre_chaine()
- la fonction
gonfler_pneus()
- la fonction
-
Classes d' Objets modélisant des Êtres vivants :
-
Classe Personne :
-
Attributs pour un objet de Classe Personne :
- la variable stockant sa
taille
- la variable stockant son
poids
- la variable stockant sa
date_naissance
- la variable stockant sa
couleur_cheveux
- la variable stockant sa
couleur_yeux
- la variable stockant son
metier
- la variable stockant son
niveau_d_etudes
- la variable stockant sa
-
Méthodes pour un objet de Classe Personne :
- la fonction
manger()
- la fonction
parler()
- la fonction
chanter()
- la fonction
dormir()
- la fonction
faire_les_courses()
- la fonction
travailler()
- la fonction
apprendre()
- la fonction
-
-
Classe Chat :
-
Attributs pour un objet de Classe Chat :
- la variable stockant sa
taille
- la variable stockant son
poids
- la variable stockant sa
date_naissance
- la variable stockant sa
couleur_pelage
- la variable stockant sa
couleur_yeux
- la variable stockant son
proprietaire
- la variable stockant son
nombre_moustaches
- la variable stockant sa
-
Méthodes pour un objet de Classe Chat :
- la fonction
manger()
- la fonction
parler()
- la fonction
chanter()
- la fonction
dormir()
- la fonction
chasser()
- la fonction
griffer()
- la fonction
-
Classes d'Objets modélisant un concept intelectuel et/ou abstrait :
-
Classe Compte :
-
Attributs pour un objet de Classe Compte :
- la variable stockant le
nom_proprietaire
du compte - la variable stockant le
numero
de compte - la variable stockant son
solde
- la variable stockant sa
date_de_creation
- la variable stockant le
-
Méthodes pour un objet de Classe Compte :
- la fonction
faire_virement()
- la fonction
ajouter_destinataire()
- la fonction
demander_carte_bleue()
- la fonction
-
-
Classe Tableau :
-
Attributs pour un objet de Classe Tableau :
- la variable stockant le
nombre_d_elements
du Tableau
- la variable stockant le
-
Méthodes pour un objet de Classe Tableau :
- la fonction
minimum_des_elements()
du Tableau - la fonction
maximum_des_elements()
- la fonction
trier_les_elements_ordre_croissant()
- la fonction
extraire_premier_element()
- la fonction
extraire_dernier_element()
- la fonction
additionner_tous_les_elements()
- la fonction
moyenne_tous_les_elements()
- la fonction
-
-
Classe Graphe :
-
Attributs pour un objet de Classe Graphe :
- la variable stockant le
nombre_de_sommets
du Graphe - la variable stockant le
nombre_d_arcs
- la variable stockant le
-
Méthodes pour un objet de Classe Graphe :
- la fonction
liste_sommets()
du Graphe - la fonction
ajoute_sommet()
- la fonction
supprime_sommet()
- la fonction
liste_arcs()
- la fonction
ajoute_arc()
- la fonction
supprime_arc()
- la fonction
degre()
- la fonction
-
Attributs distincts pour Objets distincts⚓︎
Pte
Les différentes instances d'une même classe ne différent entre elles que par les différences entre les valeurs de leurs Attributs.
Interface⚓︎
Méthodes Publiques vs méthodes Privées⚓︎
Certaines méthodes (pas forcément toutes) constituent la partie visible de l'objet (depuis l'extérieur de la Classe: e.g. depuis un autre objet, ou plus généralement depuis la partie principale de l'algorithme).
méthode publique vs méthode privée
- Une méthode accessible depuis l'extérieur de la Classe est appelée une
méthode publique . Pour qu'une méthode soit définie comme publique, certains langages utilisent le mot-clépublic lors de la définition de la méthode : c'est ce que l'on appelle un modificateur d'accès ou un access modifier
.
- Une méthode accessible uniquement depuis l'intérieur de la Classe est appelée une
méthode privée . Pour qu'une méthode soit défiie comme privée, certains langages utilisent le modificateur d'accèsprivate lors de la définition de la méthode.
Interface & Méthodes Publiques⚓︎
C'est au travers de ces méthodes publiques que l'on s'adresse à l'Objet depuis l'extérieur de la Classe :
Interface & méthodes publiques
L'ensemble des signatures de toutes ces méthodes publiques s'appelle une Interface (de programmation). L'interface de programmation permet donc de savoir comment utiliser un objet? Que peut-on faire avec lui? Que peut-on lui demander?
Attributs Publics, Privés, Protégés. Encapsulation⚓︎
Dans certains langages (Javascript, Java, C++, PHP, etc..) les attributs d'un Objet peuvent être:
- public
- private
- protected
Encapsulation
Cela permet que certains attributs soient inaccessibles, partiellement ou totalement, depuis l'extérieur de la Classe (en particulier depuis d'autres objets): dans ce cas on parle d'
en Python
Dans le langage Python, on utilise :
- deux caractères underscore
__
devant le nom de l'attribut, pour dire que l'attribut est privé / private - un seul caractère underscore
_
devant le nom de l'attribut, pour dire que l'attribut est protégé / protected
nomObjet.__attributPrive = 2
nomObjet._attributProtege = "Bonjour"
Remarquez qu'en Python, l'utilisation d'un unique underscore _
pour définir l'attribut comme protégé :
- est une simple convention de nommage, en particulier :
- Python n'empêche ni l'accès à la variable protégée, ni sa modification... ce qui est anti-intuitif
Par contre, l'utilisation d'un double underscore __
est plus restrictive:
Toute tentative d'accès à la variable d'instance __attributPrive
de l'objet nomObjet
depuis l'extérieur, se soldera par une erreur:
AttributeError: 'nomClasse' object has no attribute '__attributPrive'
Langage Python⚓︎
Pour créer des Objets, il FAUT OBLIGATOIREMENT, AU PRÉALABLE, avoir défini une Classe.
Le mot-clé self
⚓︎
Une fois un Objet créé en ayant instancié la Classe souhaitée, il semble légitime de souhaiter/pouvoir accéder aux attributs et méthodes de cet Objet courant :
- depuis l'intérieur de la Classe : par exemple, accéder à un attribut et/ou à une méthode, depuis une autre méthode de la Classe
- depuis l'extérieur de la Classe (ou bien, souhaiter que ce ne soit pas possible, par sécurité, dans certains contextes)
Pour résoudre ce genre de problèmes, on est amené à inventer et utiliser un mot-clé, self
, qui fait référence à l'instance courante de la Classe.
Autrement dit, self
(=soi-même) fait référence à l'instance de l'Objet courant qui souhaite accéder aux attributs et aux méthodes.
self
:
this
en JavasScript, Java, C++$this
en PHP@
en Ruby, etc..
Le Constructeur __init__()
⚓︎
Il semble légitime de souhaiter/devoir/pouvoir initialiser un objet, lors de sa création, avec des valeurs par défaut.
On utilise pour cela la fonction magique __init__()
qui prendra en argument le mot-clé self
, au minimum.
La méthode magique __init__()
est appelée AUTOMATIQUEMENT APRÈS la création de l'objet.
Définition d'une Classe en Python⚓︎
Exemple de Classe⚓︎
class Personne:
def __init__(self, prenom, nom="DUPOND", ville="Marseille"):
self.age = 33
self.__prenom = prenom
self._nom = nom
self.ville = ville
def saluer(self):
print("Salut",self.__prenom)
def __str__(self):
return "Nom: {} {}, Âge: {}, Habite à {}".format(self.__prenom,self._nom,self.age,self.ville)
Instancier la Classe⚓︎
Nous sauvegardons le code précédent définissant la Classe Personne
, dans le fichier classPersonne.py
.
Voici quelques exemples d'instanciation de la Classe Personne, à ajouter après la définition de la classe Personne
:
moi = Personne("Laurent")
julie = Personne("Julie")
print(moi.age)
print(moi)
julie.saluer()
print(julie._nom)
Exécuter ce fichier comme un script⚓︎
On peut ensuite exécuter ce fichier comme un script de la manière usuelle:
$ cd (chemin ou se trouve votre fichier)
$ python classPersonne.py
33
Nom: Laurent DUPOND, Âge: 33, Habite à Marseille
Salut Julie
DUPOND
Utiliser/Importer ce fichier comme un module⚓︎
Comprendre que nous avons d'abord un problème à résoudre⚓︎
Comme tout fichier en .py
, ce fichier classPersonne.py
peut être vu comme un module Python.
On pourrait donc souhaiter :
- Importer le module
classPersonne
ainsi défini dans un autre fichier Python, pour pouvoir récupérer/utiliser toutes les fonctionnalités de la ClassePersonne
, mais dans un autre fichier.py
. Remarquons au passage que cette manière de travailler est bien meilleure, car modulaire donc plus lisible, et plus facilement maintenable. - Importer le module
classPersonne
dans un Terminal (Interactif) Python, afin de faire du débuggage, et voir le résultat produit instantanément en ligne de commandes
Dans chacun de ces deux cas, on s'aperçoit que les lignes \(1\) à \(6\), que l'on avait placées après la définition de la Classe Personne
pour faire des tests d'instanciation, vont être également exécutées.
Or, s'il semble intéressant de pouvoir exécuter ces lignes lors de l'éxécution du fichier comme un script, il semble également intéressant que ces lignes ne soient plus exécutées :
- lors de l'import de ce module dans un autre fichier, car dans ce cas ill semble légitime de penser que l'on n'est plus en mode débuggage
- lors de l'import de ce module dans un Terminal interactif Python, car dans ce cas, on souhaite probablement plutôt interagir avec la Classe
Personne
en ligne de commande
On souhaiterait pourtant conserver ces lignes lorsque le fichier est exécuté en mode script.
Comment résoudre ce problème?⚓︎
Tous les modules sont des Objets en Python, donc ils disposent d'attributs et de méthodes.
Pour résoudre ce problème qui peut sembler à priori insoluble, Python utilise l'attribut __name__
du module classPersonne
if __name__ == "__main__":
# Ces lignes sont exécutées si le fichier est exécuté comme un script
# mais PAS si importé comme un module dans un autre fichier .py ( /par un autre module),
# NI si importé comme module depuis un Terminal
Cela résout donc parfaitement notre problème!
Votre module classPersonne
(donc le fichier classPersonne.py
) doit donc maintenant contenir :
class Personne:
def __init__(self, prenom, nom="DUPOND", ville="Marseille"):
self.age = 33
self.__prenom = prenom
self._nom = nom
self.ville = ville
def saluer(self):
print("Salut",self.__prenom)
def __str__(self):
return "Nom: {} {}, Âge: {}, Habite à {}".format(self.__prenom,self._nom,self.age,self.ville)
if __name__ == "__main__":
moi = Personne("Laurent")
julie = Personne("Julie")
print(moi.age)
print(moi)
julie.saluer()
print(julie._nom)
Hein ? Quoi? Pourquoi? Qu'est-ce que ça veut dire le __name__
? et le __main__
?⚓︎
En théorie, la variable __name__
, qui est donc un attribut existant pour tout module Python, contient le nom du module sous forme d'une chaîne de caractère (str
).
En pratique néanmoins, __name__
prend des valeurs particulières et différentes selon le module dans lequel il est exécuté, ainsi :
__name__ = "__main__"
, dans l'un des trois cas suivants :- lorsque le module (c'est-à-dire le fichier
.py
) est lu à partir de l'entrée standard, - lorsqu'il est exécuté comme un script,
- lorsqu'il est lancé à partir d'une invite interactive.
__name__ = "nom_du_module_importé"
(c'est-à-dire en pratique, le nom du fichier.py
importé comme un module) lorsque celui-ci est importé comme module :- depuis un autre module (c'est-à-dire depuis un autre fichier
.py
), ou bien, - depuis un Terminal
Cette condition if __name__ == "__main__":
est donc ajoutée afin que le code qui lui succède :
* Soit exécuté s'il est lancé comme un script
* MAIS PAS s'il est importé comme un module (ni depuis un autre fichier, ni depuis un Terminal interactif)
Exemple d'Utilisation/Importation de la Classe Personne
depuis un Terminal interactif⚓︎
On importe la classe Personne
du module classPersonne
, en tapant dans un Terminal :
# le répertoire courant DOIT être celui où se trouve votre fichier `classPersonne.py`
$ ipython # pour entrer dans le Terminal interactif
Python 3.8.6 (default, Sep 30 2020, 04:00:38)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from classPersonne import Personne
La syntaxe générale est donc:
In [1]: from nomDuModule import NomDeLaClasse
On peut alors utiliser la classe Personne
depuis le Terminal interactif, et accéder à tous ses attributs et toutes ses méthodes
In [1]: from classPersonne import Personne
In [2]: paul=Personne("Paul")
In [3]: print(paul)
Nom: Paul DUPOND, Âge: 33, Habite à Marseille
In [4]: paul.age
Out[4]: 33
In [5]: paul._nom
Out[5]: 'DUPOND'
In [6]: paul.__prenom
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-6-6e451405cdf3> in <module>
----> 1 paul.__prenom
AttributeError: 'Personne' object has no attribute '__prenom'
Et OUI! C'est normal, rappelons-nous que __prenom
est un attribut privé, et nous sommes en train de tenter d'accéder à l'attribut __prenom
(depuis le Terminal interactif, donc) depuis l'extérieur de la Classe...
Exemple d'Utilisation/Importation de la Classe Personne
depuis autre module⚓︎
Dans le dossier courant, celui qui contient votre fichier/module classPersonne.py
, créer un nouveau fichier nommé test.py
, et entrer les instructions suivantes:
# ceci est le fichier test.py (i.e. module test)
from classPersonne import Personne
laura = Personne("Laura")
laura._nom = "DURAND"
laura.age = 19
laura.ville = "Paris"
laura.saluer()
print(laura.age)
print(laura.ville)
print(laura)