Exercices de POO - série 1
Exercice 1 : Un exemple pas à pas - Bilbo et Gollum⚓︎
Création de la classe
Nous allons commencer par écrire une classe Personnage
(qui sera dans un premier temps une coquille vide) et, à partir de cette classe, créer 2 instances : bilbo
et gollum
.
Tester :
Pour l'instant, notre classe ne sert à rien et nos instances d'objet ne peuvent rien faire. Comme il n'est pas possible de créer une classe totalement vide, nous avons utilisé l'instruction pass
qui ne fait rien. Ensuite nous avons créé 2 instances de la classe Personnage
: bilbo
et gollum
.
Le constructeur : la méthode __init__
Les attributs de l'objet doivent être définis dans la classe, à l'aide d'une méthode d'initialisation des attributs.
Une méthode particulière, nommée le constructeur, permet de définir les attributs dès l'instanciation d'un objet.
Cette méthode est définie dans le code source par la ligne : def __init__ (self):
Rappel : La méthode __init__
La méthode __init__
est automatiquement exécutée au moment de la création d'une instance.
Le mot self
est obligatoirement le premier argument d'une méthode.
Le mot self
représente l'instance. Quand vous définissez une instance de classe (bilbo
ou gollum
) le nom de votre instance va remplacer le mot self
.
Dans le code source, nous allons avoir :
class Personnage_1:
def __init__ (self):
self.vie = 20
gollum
, Python va créer l'attribut vie
de la variable gollum
.Cet attribut aura pour valeur de départ la valeur donnée à
self.vie
dans la méthode __init__
Il se passera exactement la même chose au moment de la création de l'instance bilbo
, on aura automatiquement la création de l'attribut vie
de la variable bilbo
.
Exécutez ce code, puis dans la console, faites afficher les valeurs des attributs vie
de gollum
et de bilbo
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
En console saisir et exécuter ligne par ligne:
>>> gollum.vie
>>> bilbo.vie
Passer un argument
Imaginons que nos deux personnages n'aient pas au départ les mêmes points de vie ! Pour l'instant, impossible d'introduire cette contrainte (self.vie = 20
)
Une méthode, comme une fonction, peut prendre des paramètres.
Le passage de paramètres se fait au moment de la création de l'instance. Modifiez le code pour que le nombre de vies soit un paramètre dont la valeur sera fixée lors de l'instanciation.
Votre code doit :
- Permettre de passer un argument
nb_vies
. - Créer une instance de
Personnage
nomméebilbo
initialisée avec 20 vies. - Créer une autre instance,
gollum
, avec 15 vies. - Afficher les valeurs de l'attribut
vie
pourbilbo
- Afficher les valeurs de l'attribut
vie
pourgollum
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
class Personnage_2:
def __init__(self, nb_vies):
self.vie = nb_vies
bilbo = Personnage_2(20)
gollum = Personnage_2(15)
print(bilbo.vie)
print(gollum.vie)
Passer deux arguments
Compléter le code pour :
- Permettre de passer deux paramètres au constructeur.
- Utiliser les paramètres
nb_vies
etage
pour initialiser les attibutsvie
etage
. - Créer une instance,
gollum
, avec 20 vies et 127 ans. - Afficher ceci (en utilisant les attributs) :
gollum a 127 ans et 20 vies
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
class Personnage_3:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
gollum = Personnage_3(20, 127)
print("gollum a ", gollum.age, " ans et ", gollum.vie, " vies")
Ajouter des méthodes
Votre code doit :
- Ajouter une méthode
perd_une_vie
qui modifie l'attibutvie
(retire une vie) - Ajouter une méthode
donne_etat
qui renvoie la valeur de l'attibutvie
- Créer un seul personnage,
gollum
, avec 20 vies et 127 ans. - Créer une variable
etat_1
égale à son nombre de vie, puis l'afficher - Modifier le nombre de vies avec la méthode
perd_une_vie
- Créer une variable
etat_2
égale à son nouveau nombre de vie, puis l'afficher.
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
class Personnage_4:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_une_vie(self):
self.vie = self.vie - 1
gollum = Personnage_4(20, 127)
etat_1 = gollum.donne_etat()
print(etat_1)
gollum.perd_une_vie()
etat_2 = gollum.donne_etat()
print(etat_2)
Mauvaise pratique
Vous avez sans doute remarqué que lors de "l'utilisation" des instances bilbo
et gollum
, nous avons uniquement utilisé des méthodes et nous n'avons plus directement utilisé des attributs (plus de gollum.vie
). Il est important de savoir qu'en dehors de la classe l'utilisation des attributs est une mauvaise pratique en programmation orientée objet : les attributs doivent rester "à l'intérieur" de la classe, l'utilisateur de la classe ne doit pas les utiliser directement. Il peut les manipuler, mais uniquement par l'intermédiaire d'une méthode (la méthode perd_une_vie
permet de manipuler l'attribut vie
)
Boire une potion
Nos personnages peuvent boire une potion qui leur ajoute un point de vie.
Vous devez :
- Modifier la classe
Personnage
en ajoutant une méthodeboire_potion
qui ajoute un point de vie. - créer en dehors de la classe une fonction
simul(n, a)
qui crée un personnage avecn
vies, un âgea
, lui fait boire une potion, et renvoie le nombre de vies.
Vous pourrez tester par exemple simul(10, 127)
dans la console.
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
class Personnage_5:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_une_vie(self):
self.vie = self.vie - 1
def boire_potion(self):
self.vie = self.vie + 1
def simul(n, a):
mon_personnage = Personnage_5(n, a)
mon_personnage.boire_potion()
return mon_personnage.donne_etat()
Perdre plusieurs vies
Selon le type d'attaque subie, le personnage peut perdre plus ou moins de points de vie. Pour tenir compte de cet élément, remplacer la méthode perd_une_vie
par la méthode perd_vies
qui prend le nombre de vies perdues vies_perdues
en paramètre.
Vous devez :
- écrire la méthode
perd_vies
- instancier
gollum
avec 15 vies et 100 ans - lui faire perdre 2 vies avec la méthode
perd_vies
- Faire afficher le nombre de vies avec la méthode
donne_etat
Contrainte
vous ne pouvez pas utiliser la notation pointée gollum.vie
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
class Personnage_6:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_vies(self, vies_perdues):
self.vie = self.vie - vies_perdues
def boire_potion(self):
self.vie = self.vie + 1
gollum = Personnage_6(15, 100)
gollum.perd_vies(2)
print(gollum.donne_etat())
Un peu de hasard ne nuira pas...
Modifier le code précédent, de façon que perd_vies(self, vies_perdues)
retire entre 1 et vies_perdues
vies au personnage attaqué.
Vous devez :
- Modifier la méthode
perd_vies
- Compléter le code de façon à créer un personnage ayant 100 vies, 130 ans, puis qui subit 3 attaques consécutives, lui infligeant chacune 1 à 10 vies perdues... Il faudra ensuite afficher son nombre de vies.
Vous pouvez aussi imaginer vos propres scénarios, en rajoutant le fait de boire de la potion ...
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
from random import randint
class Personnage_7:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_vies(self, vies_perdues):
perdues = randint(1, vies_perdues)
self.vie = self.vie - perdues
def boire_potion(self):
self.vie = self.vie + 1
monstre = Personnage_7(100, 130)
for i in range(3):
monstre.perd_vies(10)
print(monstre.donne_etat())
Plus mort que mort ?
La méthode perd_vies
doit être écrite de façon à ne jamais renvoyer un nombre de vies négatif. Si le nombre de vies est négatif, il doit être mis à 0.
Vous devez :
- Modifier la méthode
perd_vies
- Completer le code de façon à créer un personnage ayant 100 vies puis qui subit des attaques consécutives, lui infligeant chacune 1 à 10 vies perdues, jusqu'à ce qu'il n'ait plus aucune vie. Le code affichera le nombre d'attaques subies.
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
from random import randint
class Personnage_8:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_vies(self, vies_perdues):
perdues = randint(1, vies_perdues)
self.vie = self.vie - perdues
if self.vie < 0:
self.vie = 0
def boire_potion(self):
self.vie = self.vie + 1
monstre = Personnage_8(100, 130)
cpt = 0
while monstre.donne_etat() > 0:
monstre.perd_vies(10)
cpt = cpt + 1
print(monstre.donne_etat())
print("Il y a eu ", cpt, " attaques")
Un combat
Organisez un combat virtuel entre nos 2 personnages Bilbo et Gollum:
-
Le code décide aléatoirement quel personnage va attaquer en premier
-
Tant que Bilbo et Gollum sont en vie:
- Un personnage attaque (la victime perd de 1 à 10 vies)
- On change de personnage
Tant qu'aucun des deux n'est mort, le combat continue
- Quand un des deux est mort, on affiche le nombre d'attaques qui ont été menées durant le combat, et l'état de chaque personnage.
Aide pour alterner les combattants
On peut utiliser une variable attaquant = randint(0, 1)
Pour changer d'attaquant, on peut écrire attaquant = 1 - attaquant
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
from random import randint
class Personnage_9:
def __init__(self, nbre_vies, age):
self.vie = nbre_vies
self.age = age
def donne_etat(self):
return self.vie
def perd_vies(self, vies_perdues):
perdues = randint(1, vies_perdues)
self.vie = self.vie - perdues
if self.vie < 0:
self.vie = 0
def boire_potion(self):
self.vie = self.vie + 1
gollum = Personnage_9(100, 127)
bilbo = Personnage_9(100, 127)
nb_attaques = 0
attaquant = randint(0, 1)
while gollum.donne_etat() > 0 and bilbo.donne_etat() > 0 :
if attaquant == 0 :
gollum.perd_vies(10)
else :
bilbo.perd_vies(10)
nb_attaques = nb_attaques + 1
attaquant = 1 - attaquant
print(nb_attaques)
print("Gollum a ", gollum.donne_etat(), "vies")
print("bilbo a ", bilbo.donne_etat(), "vies")
Facultatif : Faites vos propres règles et implémentez les
Il n'y aura pas de correction toute faite à cette question ... 😊
Modifiez (à votre convenance) les règles et améliorez le programme en modifiant des méthodes ou en implémentant vos propres méthodes.
Quelques propositions si vous ne voyez pas trop quoi ajouter : * Quand une personne attaque, elle peut en réalité décider de ne pas le faire et à la place, boire une potion qui lui rend par exemple 1-8 vies. Le code devra activer cette action si perso.vie est trop bas (à vous de préciser!) * Un personnage peut se mettre en fuite, dans ce cas par exemple, il passe son tour, l'autre peut porter une dernière attaque, mais le combat s'arrête ensuite * Les possibilités sont infinies, ajouter une attaque spéciale, ajouter une vie à chaque tour (autoguérison) etc.
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Exercice 2 : exercice "papier"⚓︎
Les comptes
Créez une classe Compte
. Un objet de type Compte
devra posséder 4 attributs :
- solde : float : le solde du compte - lors de la création du compte le solde sera 0
- nom: str: le nom du titulaire du compte
- prenom: str: le prénom du titulaire du compte
- num_compte: int : un entier identifiant du compte
Les 3 derniers paramètres devront être définis lors de l'instanciation d'un compte.
Ajoutez des méthodes :
- une méthode str qui permettra l'affichage du compte avec
print()
. La méthode doit renvoyer une chaine de caractères comme :
Nom : DURAND
Prénom : Jacques
Solde : 200
👉 pour insérer des retours à la ligne dans une chaîne on ajoute le caractère "\n"
-
une méthode
ajouter
qui permettra de verser de l'argent sur le compte -
une méthode
debiter
qui permettra de retirer de l'argent du compte.
La méthodedébiter
doit effectuer le retrait si le solde est suffisant (supérieur au montant qu'on souhaite retirer). Sinon elle doit afficher un message et ne pas effectuer le débit. -
une méthode
get_solde
qui renvoie le solde du compte.
Enfin, vous ajouterez dans votre code les instructions pour créer un compte, verser de l'argent puis effectuer un débit.
Solution
class Compte:
def __init__(self, nom ,prenom, numero ) -> None:
"""
params : nom: str; prenom: str; numero: int (numéro de compte)
Le constructeur initialise les attributs, solde est initialisé à 0
"""
self.solde = 0
self.nom = nom
self.prenom = prenom
self.num_compte = numero
def __str__(self) -> str :
"""
param : self : un objet de type compte
sortie : la fonction renvoie une chaîne de caractère. __str__ est utilisée par print()
"""
return "Nom : "+self.nom+"\nPrénom : "+self.prenom+"\nSolde : "+str(self.solde)
def ajouter(self, montant: float) -> None:
self.solde = self.solde + montant
def debiter(self, montant:float) -> None:
if self.solde >= montant :
self.solde = self.solde - montant
else:
print( 'solde insuffisant' )
def get_solde(self) -> float:
return self.solde
mon_compte = Compte('Durand', 'Jacques', 13215)
mon_compte.ajouter(200)
mon_compte.debiter(20)
print(mon_compte)
print(mon_compte.solde)
Exercice 3 : Corrigez l'erreur⚓︎
Les voitures
Le code suivant est faux. Vous devez le corriger.
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
Dans la méthode nom_puissance
les variables nom
et couleur
ne sont pas définies.
Il faut utiliser des attributs.
class Voiture:
def __init__(self, nom, couleur, puissance):
self.nom = nom
self.couleur = couleur
self.puissance = puissance
def nom_puissance(self):
return self.nom + " - puissance : " + str(self.puissance)
voiture_1 = Voiture("Coccinelle", "rouge", 5)
print(voiture_1.nom_puissance())
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)