Contenus | Capacités attendues | Commentaires |
---|---|---|
Vocabulaire de la programmation objet : classes, attributs, méthodes, objets. | Écrire la définition d’une classe. Accéder aux attributs et méthodes d’une classe. | On n’aborde pas ici tous les aspects de la programmation objet comme le polymorphisme et l’héritage. |
La programmation orientée objet est un paradigme de programmation permettant à l'utilisateur de dépasser les objets proposés par le langage de programmation afin d'en créer de nouveaux adaptés au problème réel qu'il tente de résoudre.
Les objets sont décrits dans des class
es contenant:
En Python, on créé une classe avec la mot clé class
qu'on nomme par habitude avec un nom en
CamelCase.
class MaClasse:
nom = "Terminale"
L'objet MaClasse
est une sorte de patron à partir duquel on va pouvoir créer des objets à la
demande en créant ce que l'on appelle des instances par appel de la classe.
## On crée deux instances de l'objet Maclasse
classe1 = MaClasse()
classe2 = MaClasse()
Notre classe contient un seul attribut x qui peut être retourné à l'aide de la notation pointée: nom_instance.x
.
# nos deux instances contiennent le même attribut x = 4
classe1.nom
'Terminale'
classe2.nom
'Terminale'
On peut modifier les attributs d'un objet ou les supprimer.
# méthode déconseillée
# on utilise plutôt des getters et setters pour ça (voir plus bas)
classe2.nom = "Première"
# l'attribut x a bien été modifié pour l'instance classe2
classe2.nom
'Première'
# par contre l'attribut de l'instance classe1 est inchangé
classe1.nom
'Terminale'
del classe1.nom
classe1.nom
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-18-e51cde97e415> in <module>
----> 1 del classe1.nom
2 classe1.nom
AttributeError: nom
self
Les méthodes sont des fonctions définies au sein de la classe.
Une méthode prend toujours en premier paramètre l'objet lui-même par l'intermédiare de l'argument self
.
L'appel de la méthode se fait également avec la notation pointée: nom_instance.methode(...)
class MaClasse:
nom = 'Terminale'
def ajoute_lycée(self, lycée):
"""Cette méthode modifie l'attribut nom et le renvoie"""
self.nom = self.nom + " du lycée " + lycée
return self.nom
classe1 = MaClasse()
# appel de la méthode pour ajouter le nom du lycée et le renvoer et le renvoyer
classe1.ajoute_lycée("Honoré d'Estienne d'Orves")
"Terminale du lycée Honoré d'Estienne d'Orves"
# l'attribut x a bien été modifié
classe1.nom
"Terminale du lycée Honoré d'Estienne d'Orves"
__init__()
Il est souvent interressant de créer des objets différents à partir d'un même classe , il est donc possible d'ajouter des arguments qui seront pris en charge lors de l'instanciation de l'objet en utilisant la méthode prédéfinie: __init__()
.
Prenons l'exemple d'une classe plus réaliste consitant à représenter une personne.
class Personne:
def __init__(self, nom, age):
self.nom = nom
self.age = age
jim = Personne("Jim", 27)
print(jim.nom)
print(jim.age)
Jim
27
__repr__()
Cette méthode est utilisée pour donner une représentation des objets sous forme lisible par exemple lors d'un appel de la fonction print
.
Pour l'instant si on affiche notre instance, on a:
print(jim)
<__main__.Personne object at 0x7f64a010d4f0>
class Personne:
def __init__(self, nom, age):
self.nom = nom
self.age = age
def __repr__(self):
return f"{self.nom} est une Personne de {self.age} ans."
john = Personne("John", 32)
print(john)
john
John est une Personne de 32 ans.
John est une Personne de 32 ans.
Il est fortement déconseillé de récupérer (get) ou modifier (set) des attributs de l'objet directement par l'utilisation de la notation pointée vue précédemment.
Pour chaque attribut, il est conseillé de définir deux méthodes:
get_nom_attribut
: pour le récupérer.set_nom_attribut
: pour le modifier.C'est long oui, mais c'est la pratique couramment recommandée.
Voici ce que cela donnerait dans notre cas, on a deux attributs: nom
et age
, il faut donc ajouter quatre méthodes.
class Personne:
def __init__(self, nom, age):
self.nom = nom
self.age = age
def get_nom(self):
return self.nom
def set_nom(self, nom):
self.nom = nom
def get_age(self):
return self.age
def set_age(self, age):
self.age = age
def __repr__(self):
return f"{self.nom} est une Personne de {self.age} ans."
john = Personne("John", 32)
print("Au début")
print(john)
print("Modification des attributs avec les setters")
john.set_nom("Jean")
john.set_age(12)
print(john)
print("Récupération des attributs avec les getters")
john.get_nom(), john.get_age()
Au début
John est une Personne de 32 ans.
Modification des attributs avec les setters
Jean est une Personne de 12 ans.
Récupération des attributs avec les getters
('Jean', 12)
Un des aspects intéressants (mais hors-programme) est la possibilité de créer des sous classes qui héritent des attributs et méthode de la classe parente.
L'héritage q'il est bien réalisé permet d'éviter des répétitions de code (Principe DRY: Don't Repeat Yourself), et permet d'aboutir à une grande structuration des données.
class Eleve(Personne):
def __init__(self, nom, age, classe):
# super appelle le constructeur du parent
super().__init__(nom, age)
self.classe = classe
# On ne met à jour que les méthodes qui sont changées
def __repr__(self):
return f"Bonjour, je suis {self.nom}, j'ai {self.age} et je suis en {self.classe}"
albert = Eleve("Albert", 27, 'nsi')
albert
Bonjour, je suis Albert, j'ai 27 et je suis en nsi
Toutes les méthodes du parent non modifiées sont héritées.
albert.get_age(), albert.get_nom()
(27, 'Albert')
Il en reste cepenant à définir propre à cet objet: get_classe()
, set_classe()
, et peut-être d'autres (travaille()
, bavarde()
...)