Jusqu’à présent nous n'avions utilisé que des objets prédéfinis, de type natif :
int
, float
, bool
, str
, list
, tuple
, dict
, ...
Nous avons même appris à utiliser des méthodes associées à ces types, comme ma_liste.append(valeur)
.
Une variable de type int
est en fait un objet de type int
donc construit à partir de la classe
int
. De même pour les float
et string
. Mais également pour les list
, tuple
, dict
, etc.
En POO, on peut créer ses propres objets qui auront leurs méthodes, ce qui aura pour effet:
Une classe (= un concept, abstrait) définit des objets (= représentants de ce concept, concret) qui sont des instances de cette classe.
On utilisera le mot objet ou instance pour désigner la même chose.
Pour créer une classe on utilise le mot-clé : class
suivi par le nom de la classe et des incontournables " : ".
Le nom de la classe commence par une majuscule et ne contient que des caractères alphanumériques.
class Voiture : # définition de la classe Voiture
pass
Les objets peuvent posséder des attributs (variables associées aux objets) et des méthodes (qui sont des fonctions associées aux objets et qui peuvent agir sur ces derniers ou encore les utiliser).
Il existe trois principaux types de méthodes différentes :
- celles qui permettent de construire un objet,
- celles qui permettent d'accéder à un attribut,
- celles qui permettent de modifier un objet.
Le constructeur est une méthode particulière que l'on nomme __init__
(avec deux underscores de chaque
côté...) et un premier paramètre nommé self
. Le constructeur ne doit pas renvoyer de résultat.
Le constructeur est implicitement exécuté lors de la création de chaque nouvelle instance.
class Voiture : # définition de la classe Voiture
# Constructeur simple
def __init__(self) :
self.couleur = "rouge"
self.portes = 2
self.places = 4
self.moteur = "diesel"
clio = Voiture() # instanciation d'un objet clio
type(clio)
clio.
ici, tous les objets seront des voitures rouges à 2 portes 4 places diesel...
Le constructeur peut permettre de passer des paramètres aux attributs afin de personnaliser une instance.
class Voiture: # définition de la classe Voiture
# Constructeur paramétré
def __init__(self, couleur : str, portes : int) :
self.couleur = couleur
self.portes = portes
self.places = 4
self.moteur = "diesel"
clioOuiOui = Voiture('jaune', 3) # instanciation d'un objet de type Voiture particulier
clioToto = Voiture('verte', 5) # instanciation d'un autre objet de type Voiture différent
clioOuiOui.
cli
class Voiture: # définition de la classe Voiture
# Constructeur
def __init__(self, couleur : str, portes : int) :
self.couleur = couleur
self.portes = portes
self.vitesse = 0
# méthode pour modifier la valeur de l'attribut vitesse :
def fixeVitesseRegulateur(self, vitesse : int) :
self.vitesse = vitesse
# méthode pour accéder à la valeur de l'attribut vitesse :
def donneVitesseRegulateur(self) :
return self.vitesse
clio = Voiture('rouge', 3) # instanciation de l’objet clio
clio.donneVitesseRegulateur()
clio.fixeVitesseRegulateur(110)
print(f"La vitesse du régulateur est maintenant réglée sur {clio.donneVitesseRegulateur()} km/h")
import random
class Personnage : # définition de la classe Personnage
# Construtreur
def __init__(self, nbreDeVie) :
self.vie = nbreDeVie # attribut
# méthode pour accéder à la valeur de l'attribut vie :
def donneEtat (self) :
return self.vie
# méthode pour modifier la valeur de l'attribut vie
def perdVie (self) :
if random.random() > 0.5:
nbPoint = 1
else :
nbPoint = 2
self.vie = self.vie - nbPoint
def game() :
bilbo = Personnage(20) # instanciation d'un objet de type Personnage
gollum = Personnage(20) # instanciation d'un autre objet de type Personnage
while bilbo.donneEtat() > 0 and gollum.donneEtat() > 0 :
bilbo.perdVie()
gollum.perdVie()
if bilbo.donneEtat() <= 0 and gollum.donneEtat() > 0:
msg = f"Gollum est vainqueur, il lui reste encore {gollum.donneEtat()} points alors que Bilbo est mort"
elif gollum.donneEtat() <= 0 and bilbo.donneEtat() > 0:
msg = f"Bilbo est vainqueur, il lui reste encore {bilbo.donneEtat()} points alors que Gollum est mort"
else :
msg = "Les deux combattants sont morts en même temps"
return msg
game()
L'encapsulation consiste à rendre privés les attributs d’un objet pour cacher la représentation interne des classes, qui apparaissent alors comme des "boîtes noires" au programmeur.
Pour modifier ou lire un attribut il faudra passer par l'interface constituée des méthodes publiques servant à manipuler les objets : les mutateur (setter) et accesseur (getter)...
Certains langages, comme le PHP ou le Javascript, définissent de manière stricte cette visibilité en fournissant des mots-clés pour caractériser si chaque élément d’une classe est privé ou public.
En Python, il y a une convention de nommage : un attribut privé est toujours préfixé (c'est-à-dire précédé) de deux espaces soulignés (tiret du bas, celui du 8).
Remarque :
En Python, lorsque le nom d'un attribut commence par
__
, celui-ci est automatiquement renommé ainsi : >_nomClasse__nomAttribut
. Étant ainsi renommé, il n'est plus aussi aisément accessible depuis l'extérieur de la classe.Il existe un niveau intermédiaire entre privé et public que l'on nomme protégé. En Python, il suffit de préfixer l'attribut (ou la méthode) d'un espace souligné (tiret du bas ou du 8)
class Voiture: # définition de la classe Voiture
# Constructeur
def __init__(self) :
self.__vitesse = 0 # attribut __vitesse privé
# Mutateur public de l’attribut __vitesse
def set_vitesse(self, valeur : int):
if 0 <= valeur <= 130 :
self.__vitesse = valeur
# Accesseur public de l’attribut __vitesse
def get_vitesse(self) -> int:
return self.__vitesse
clio = Voiture() # instanciation de l’objet clio
clio.set_vitesse(90)
print(f"Vitesse fixée sur {clio.get_vitesse()} km/h")
Vitesse fixée sur 90 km/h
clio.__vitesse = 110
print(f"Vitesse fixée sur {clio.get_vitesse()} km/h")
Vitesse fixée sur 90 km/h
clio._Voiture__vitesse = 120
print(f"Vitesse fixée sur {clio.get_vitesse()} km/h")
Vitesse fixée sur 120 km/h
la vitesse reste inchangée !
Intérèts de l'encapsulation :
simplifier la vie du programmeur qui utilise une classe.
masquer la complexité de la classe.
permettre de modifier la classe sans changer le reste du programme.
la liste des méthodes devient une sorte de "mode d’emploi" de la classe.
isoler les attributs et des méthodes, ne permettre leur modification que par l'interface...
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. |
Contenus | Capacités attendues | Commentaires |
---|---|---|
Paradigmes de programmation. | Distinguer sur des exemples les paradigmes impératif, fonctionnel et objet. Choisir le paradigme de programmation selon le champ d’application d’un programme. |
Avec un même langage de programmation, on peut utiliser des paradigmes différents. Dans un même programme, on peut utiliser des paradigmes différents. |
développer un projet libre dans lequel vous utiliserez la programmation objet...
Ce document, basé sur le travail de Vincent GROSJEAN, David ROCHE et d'autres ressources listées plus haut, est mis à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International.
Pour toute question, suggestion ou commentaire : eric.madec@ecmorlaix.fr