TNSI : Exercices POO⚓︎
Encapsulation + Accesseurs / Mutateurs
-
Créer une classe Python nommée CompteBancaire qui représente un compte bancaire, ayant pour attributs :
- numeroCompte (type
str
), - nom (nom du propriétaire du compte du type
str
), - solde (type
float
)
On pourra utiliser un constructeur
__init__()
ayant comme paramètres :numeroCompte:str
(par défaut numeroCompte="112233"),nom:str
(par défautnom="DUPOND"
),solde:float
(par défautsolde=0
)
- numeroCompte (type
-
Créer une méthode
depot(montant:float)
qui modélise le dépôt d'un certainmontant
sur le compte :- le
solde
du compte doit être mis à jour - une confirmation de la bonne réception de l'argent sur le compte doit apparaître à l'écran (Terminal)
- le
-
Créer une méthode
retrait(montant:float)
qui gère les retraits: mise à jour dusolde
du compte \(+\) Affichage à l'écran - Créer une méthode
agios()
permettant d'appliquer les agios à un pourcentage de 5 % du solde du compte
Pour les heureux qui ne connaîtraient pas : lesagios
sont des frais d'ajournement que la banque vous déduit de votre compte, lorsque votre solde est en négatif. - Modifier la méthode précédente
agios(p:float)
de sorte qu'elle applique les agios à hauteur dep%
(et non plus forcément 5%) - Créer une méthode
infos()
permettant d’afficher les infos détaillées du compte (numeroCompte+nom+solde) -
Encapsulation
Rappel : Le concept d'encapsulation permet d’éviter une modification accidentelle (par erreur) ou non souhaitée (piratage) des données/attributs d’un objet en bloquant les droits de lecture et de modification des attributs. Pour rappel :-
Les attributs privés
self.__attributPrive
(deux underscores__
) sont accessibles UNIQUEMENT depuis l'intérieur de la classe elle-même.
En particulier, les attributs privés :- NE sont PAS accessibles depuis l'extérieur de la classe,
- NI depuis les classes filles/enfants
En ce qui concerne les attributs privés, ce comportement est correctement rendu en Python.
-
les attributs protégés
self._attributProtege
(un seul underscore_
) sont accessibles :- depuis l'intérieur de la classe elle-même, ou
- depuis l'une de ses filles/enfants
En particulier, les attributs protégés NE sont PAS accessibles de puis l'extérieur de la classe. En ce qui concerne les attributs protégés, ce comportement N'est PAS correctement rendu en Python.
Modifier l'attribut
solde
en un attribut privé, de sorte que celui-ci ne puisse pas être: ni lu, ni modifié depuis l'extérieur de la classe CompteBancaire. Adapter la classe CompteBancaire pour que celle-ci redevienne fonctionnelle. -
-
Accesseurs / Getters
et Mutateurs
/ Setters
Pour pouvoir modifier des attributs privés et/ou protégés, dans certains contextes sécurisés, on peut créer des méthodes qui jouent le rôle d’interface obligatoire:- les Accesseurs
/ Getters
sont des méthodes qui permettent de lire les attributs privés et/ou protégés, dans un contexte où ils ne devraient normalement pas l'être (en contrôlant les informations transmises). Ils sont notés usuellement
getXXX()
ouget_XXX()
oùXXX
désigne un nom à personnaliser selon le contexte. - les Mutateurs
/ Setters
sont des méthodes qui permettent de lire ET/OU de modifier les attributs privés et/ou protégés, dans un contexte où ils ne devraient normalement pas l'être (en contrôlant les informations transmises). Ils sont notés usuellement
setXXX()
ouset_XXX()
oùXXX
désigne un nom à personnaliser selon le contexte.
Écrire la méthode
getSolde()
(un getter) qui renvoie la valeur de l'attribut privé__solde
: cette méthode est appelable depuis l'extérieur de la classe (testez-la). Écrire la méthodesetSolde(valeur)
(un setter) qui modifie la valeur de l'attribut privé__solde
avec la nouvellevaleur
passée en paramètre: cette méthode est appelable depuis l'extérieur de la classe. - les Accesseurs
Héritage
# Définit une classe 'Fille' (=classe Fille/Enfant)
# qui hérite de la classe 'Mere' (=classe Mère)
class Fille(Mere):
pass
Dans le code précédent, on dit que la classe Fille
/Enfant
hérite de la classe Mere
.
En pratique, cela impliquera en particulier que:
- Toute instance de la classe
Fille
hérite également de (donc accède à) :- tous les attributs de la classe
Mere
- toutes les méthodes de la classe
Mere
- tous les attributs de la classe
- Il est possible de
surcharger les attributs et/ou les méthodes de la classeMere
, par ceux de la classeFille
/Enfant
, Cela veut dire que, on peut redéfinir dans la classeFille
, les attributs et méthodes de la classeMere
(avec EXACTEMENT le même nom), de sorte à pouvoir les remplacer/écraser/modifier dans un contexte plus spécifique :- les attributs de la classe
Fille
seront alors utilisés au lieu de ceux de la classeMere
, sur toutes les instances de la classe Fille :
ils sont plus spécifiques pour la classeFille
, par rapport à ceux de la classeMere
, donc utilisés prioritairement. - les méthodes de la classe
Fille
seront aussi utilisés au lieu de ceux de la classeMere
, sur toutes les instances de la classe Fille :
elles sont plus spécifiques pour la classeFille
, par rapport à ceux de la classeMere
, donc utilisés prioritairement.
- les attributs de la classe
On considère le code suivant :
class Personnage:
# contructeur = méthode __init__ avec 2 arguments (sans compter self !) le nombre de vies et le nom du personnage
def __init__(self, nbreDeVie, nomDuPerso):
self.vie = nbreDeVie
self.nom = nomDuPerso
# voici la méthode qui affiche le nombre de vies du personnage.
def affichePointVie(self):
print('Il reste '+str(self.vie)+' points de vie à '+self.nom)
# voici la méthode qui fait perdre 1 point de vie au personnage qui a subi une attaque
def perdVie(self):
print(self.nom+' subit une attaque, il perd une vie')
self.vie = self.vie-1
# la classe Magicien hérite de la classe Personnage
class Magicien(Personnage):
# dans def __init__ on retrouve nbreDeVie et nomDuPerso comme dans le def __init__ de la classe Personnage
def __init__(self, nbreDeVie, nomDuPerso, pointMagie):
# la ligne suivante est très importante dans le cas d'héritage, il faut systématiquement faire ce genre d'appel :
# classeparente.__init__(self,arg1,arg2.....) pour hériter de tous les attributs et méthodes de la classe Personnage
Personnage.__init__(self, nbreDeVie, nomDuPerso)
# le seul nouvel attribut est self.magie, tous les autres sont hérités de la classe Personnage
self.magie = pointMagie
# une méthode uniquement disponible pour les instances de magiciens
def faireMagie(self):
print (self.nom+' fait de la magie')
self.magie = self.magie - 1
print('Il reste '+str(self.magie)+' points de magie à '+self.nom+'.')
# les autres méthodes des instances de magicien sont héritées de la classe personnage
# on crée une instance de Magicien
gandalf = Magicien(20,'Gandalf',15)
# applique la méthode affichePointVie à gandalf, cette méthode est héritée de la classe personnage
gandalf.affichePointVie()
# applique la méthode faireMagie à gandalf, cette méthode est uniquement applicable aux instances de la classe magicien
gandalf.faireMagie()
- créer une (autre) instance de la classe
Magicien
, nomméemerlin
, avecnombreDeVie=30
,nomDuPerso="Merlin"
, etpointMagie=17
- afficher les points de vie du magicien
Merlin
- faire perdre 1 point de vie à Merlin
- créer une méthode
perdVies(nombre)
de la classePersonnage
qui:- utilise de manière répétée la méthode
perdVie()
de la même classePersonnage
(autant de fois que nécessaire) - de sorte que le nombre de vies perdues soit égale à
nombre
- utilise de manière répétée la méthode
- créer une méthode
setPointVie(nombre)
(un setter) de la classePersonnage
, qui modifie le nombre de vies du personnage, de sorte qu'il soit égal ànombre
- créer une méthode
creeVie()
de la classeMagicien
qui ajouter 1 vie au personnage - créer une méthode
creeVies(nombre)
de la classeMagicien
qui:- utilise de manière répétée la méthode
creeVie()
de la même classeMagicien
(autant de fois que nécessaire) - de sorte que le nombre de vies gagnées soit égale à
nombre
- utilise de manière répétée la méthode
- créer une nouvelle classe
Archer
qui hérite de la classePersonnage
, de sorte qu'elle dispose :- d'un attribut public
nom
, par défaut"GreenArrow"
- d'un attribut public
nbArcs
, par défautnbArcs=1
- d'un attribut public
nbFleches
, par défautnbFleches=10
On pourra créer un constructeur__init__()
avec ces deux paramètres (etself
)
- d'un attribut public
- instancier la classe
Archer
avec une variablegreenArrow
- Vérifier que l'instance
greenArrow
de la classe FilleArcher
hérite bien de tous les attributs et méthodes de la classe MèrePersonnage
. - Modifier votre code de sorte à transformer les attributs publics
nbArcs
etnbFleches
, en des attributs privés. créer des méthodes Getters et des Setters pournbArcs
, et pournbFleches
. - Créer une méthode
tirerFleche()
, qui :- met à jour le compteur du nombre de flèches
- affiche à l'écran que la flèche a été tirée
- Créer une méthode magique
__repr__()
qui formatte l'affichage de l'Archer, lors de l'utilisation d'unprint(nom)
ounom
- Comment afficher les Points de vie pour
greenArrow
? (Faites-le) Enlever des points de Vie àgreenArrow
? (Faites-le)
Classe Chaîne étendue
Coder une classe myString permettant de doter les chaines de caractères des méthodes append() et pop() faisant les mêmes opérations que celles des listes. Exemple si on crée des chaines via l'instanciation s1 = myString("Hello") et s2 = "bonjour", et on lui applique les méthodes :
print(s1.append(" world !")) # affiche 'Hello world !'
print(s2.pop(2)) # affiche 'bonjour'
Classe Temps
On dispose d’un programme permettant de créer un objet de type Temps, qui permet de manipuler un temps entré en heures, minutes et secondes.
Les secondes et les minutes doivent être inférieures à 60. Dans les méthodes ajouterSecondes()
et ajouterMinutes()
, si les secondes (ou les minutes) dépassent 59, on doit les convertir en minutes (ou respectivement en heure).
La méthode __str__()
est une méthode native qui est appelée quand on tente de convertir un objet en chaine de caractères. La méthode de cette classe renvoie une chaine de caractères sous la forme "hh : mm : ss". Par exemple, pour un objet initialisé avec les valeurs 3h,20min et 2s, la méthode renverrait "3 : 20: 2"
La méthode enSecondes()
permet de convertir le temps en secondes. La méthode estplusPetit()
compare deux objets temps et renvoie True si l'objet temps passé en paramètre est le plus grand des deux.
Compléter ce code aux endroits indiqués par ..., puis ajouter des assertions dans l’initialiseur de Temps. On devra créer deux instances de la classe Temps, avec pour valeurs 1h,59min et 45s et l'autre avec 2h,15min et 13s.
class Temps:
"""Initialise Temps (entre 1 à 4), et Valeur (entre 1 à 13)"""
def __init__(self, h, m, s):
self.heures = h
self.minutes = m
self.secondes = s
def ajouterMinutes(self, mins):
"""incrémente les minutes de la valeur mins passée en paramètre"""
self.minutes = self.minutes + mins
while ... :
self.heures += 1
self.minutes = self.minutes - 60
def ajouterSecondes(self, secs):
"""incrémente les secondes de la valeur secondes passée en paramètre"""
self.secondes = self.secondes + secs
while ... :
...
self.secondes = self.secondes - 60
def __str__(self):
"""renvoie une chaine de caractères sous la forme hh : mm : ss"""
return ...+" : "+...+" : "+...
def enSecondes(self):
"""Convertie un temps en heures/minutes/secondes en secondes"""
return ...
def estplusPetit (self, tps) :
"""Compare deux temps entre eux. Renvoie True si l'objet est plus petit que l'objet tps passé en paramètre"""
return ...
Débuggage du Code :
#Test du code
...
...
t1.ajouterSecondes(20)
assert str(t1)== "2 : 0 : 5"
assert t1.estplusPetit(t2) == True