from datetime import date
prise_bastille = date.fromisoformat("1789-07-14")
print("type:", type(prise_bastille))
print("objet: ", prise_bastille)
>>sortie
type: <class 'datetime.date'>
objet: 1789-07-14
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 (P.O.O.) est un paradigme de programmation permettant au développeur de dépasser les objets proposés par le langage de programmation afin d’en créer de nouveaux adaptés au problème qu’il tente de résoudre: des utilisateurs, des messages, des jouets…
En POO, les objets sont décrits dans des class
es contenant:
En Python, on accède aux attributs et aux méthodes grâce à la notation pointée, vous l’avez déjà utilisée car Python est un langage fortement orienté objet.
Prenons l’exemple des objets de types date
du module datetime
.
On commence par créer une date de ce type, ce que l’on appelle une instance de l’objet.
from datetime import date
prise_bastille = date.fromisoformat("1789-07-14")
print("type:", type(prise_bastille))
print("objet: ", prise_bastille)
>>sortie
type: <class 'datetime.date'>
objet: 1789-07-14
Cet objet possède des **attributs*: les données relatives à cet objet.
On y accède grâce à la notation pointée: objet.attribut
Cet objet possède des **méthodes*: les fonctions s’appliquant sur cet objet.
On y accède grâce à la notation pointée: objet.méthode(...)
'Tuesday 14 July 1789'
En Python, on créé une classe avec la mot clé class
qu’on nomme par habitude avec un nom en UpperCamelCase.
L’objet ClasseDeLycee
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 peut accéder aux attributs de nos objets à l’aide de la notation pointée: nom_instance.attribut
.
On peut modifier les attributs d’un objet après son instanciation bien que l’on préfère utiliser un constructeur pour personnliser les objets à leur instanciation comme on le verra plus loin.
# méthode déconseillée
# on utilise plutôt des getters et setters pour ça (voir plus bas)
term2.numero = 2
# les attributs ont bien été modifiés pour l'instance term2
term2.nom, term2.numero
('Terminale', 2)
('Terminale', 1)
Dans cette partie nous avons utilisé des attributs de classe sans le self
pour plus de simplicité dans cette introduction.
Par la suite, on utilisera des attributs d’instance(self.attribut
), il y a de légères différences qui sortent du cadre de ce cours.
self
Les méthodes sont des fonctions définies au sein de la classe qui s’appliquent aux objets créés grâce à cette classe.
Une méthode prend toujours en premier paramètre l’objet lui-même par l’intermédiare du paramètre qu’on appelle par convention self
.
De façon générale, le mot clé self
désignera l’instance de l’objet au sein du code de la classe.
Lorsqu’on appelle une méthode sur une instance de la classe, on utilisera encore la notation pointée: nom_instance.methode(...)
.
__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__()
.
Voici comment nous pourrions permettre de personnnaliser notre classe dès sa création.
class ClasseDeLycee:
def __init__(self, nom, numero, eleves):
self.nom = nom
self.numero = numero
self.eleves = eleves
prem7 = ClasseDeLycee("Première", 7, ["Ada Lovelace"])
print(prem7.nom, prem7.numero, prem7.eleves)
>>sortie
Première 7 ['Ada Lovelace']
On peut donner des valeurs par défaut aux paramètres dans la signature de la méthode __init__
.
__str__()
Cette méthode est utilisée pour donner une représentation des objets sous forme lisible lors d’un appel de la fonction print
.
Pour l’instant si on affiche notre instance, on a:
class ClasseDeLycee:
def __init__(self, nom="Terminale", numero=3, eleves=[]):
self.nom = nom
self.numero = numero
self.eleves = eleves
def __str__(self):
return f"<Classe de Lycée {self.nom}{self.numero}>"
term3 = ClasseDeLycee()
print(term3)
>>sortie
<Classe de Lycée Terminale3>
On peut également utiliser la méthode __repr__()
qui est plus générale et qui sera également utilisée lors d’un appel de la fonction print
si __str__
n’est pas définie.
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 trois attributs, il faut donc ajouter six méthodes.
class ClasseDeLycee:
def __init__(self, nom="Terminale", numero=3, eleves=[]):
self.nom = nom
self.numero = numero
self.eleves = eleves
def get_nom(self):
return self.nom
def set_nom(self, nom):
self.nom = nom
def get_numero(self):
return self.numero
def set_numero(self, numero):
self.numero = numero
def get_eleves(self):
return self.eleves
def set_eleves(self, eleves):
self.eleves = eleves
def __str__(self):
return f"<Classe de Lycée {self.nom}{self.numero}>"
c = ClasseDeLycee()
print("Au début")
print(c)
>>sortie
Au début
<Classe de Lycée Terminale3>
>>sortie
<Classe de Lycée Seconde15>
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 Terminale(ClasseDeLycee):
def __init__(self, numero, eleves=[]):
# super appelle le constructeur du parent
super().__init__("terminale", numero, eleves)
# On ne met à jour que les méthodes qui sont changées
# Toutes les autres méthodes sont héritées
def __str__(self):
return f"<Classe de Terminale{self.numero}>"
term7 = Terminale(7)
print(term7)
>>sortie
<Classe de Terminale7>
Toutes les méthodes du parent non modifiées sont héritées.
['Albert Einstein', 'Paul MacCartney']
Il reste cependant à définir les méthodes et attributs propres à cette classe: voeux_parcoursup
, mention_bac
…