POO : TP Pokémon en notebook seul, corrigé sans héritage

This commit is contained in:
2026-10-12 13:50:55 +02:00
parent 830a3ac4d8
commit 09391fcc8b
2 changed files with 0 additions and 645 deletions
-102
View File
@@ -642,108 +642,6 @@ C'est une **composition** d'objets : un `Pokemon` possède une liste d'objets `C
---
## Partie 5 : Héritage (hors programme)
### Exercice 8 : Sous-classes par type
```python
class PokemonFeu(Pokemon):
def __init__(self, nom, niveau=1, pv_max=100, attaque=10):
super().__init__(nom, "Feu", niveau, pv_max, attaque)
def attaquer(self, cible):
"""
Attaque avec ×2 dégâts si la cible est de type Plante.
"""
degats = self.attaque
if cible.type_pokemon == "Plante":
degats = degats * 2
print("C'est super efficace !")
print(f"{self.nom} attaque {cible.nom} et inflige {degats} dégâts !")
cible.subir_degats(degats)
class PokemonEau(Pokemon):
def __init__(self, nom, niveau=1, pv_max=100, attaque=10):
super().__init__(nom, "Eau", niveau, pv_max, attaque)
def attaquer(self, cible):
"""
Attaque avec ×2 dégâts si la cible est de type Feu.
"""
degats = self.attaque
if cible.type_pokemon == "Feu":
degats = degats * 2
print("C'est super efficace !")
print(f"{self.nom} attaque {cible.nom} et inflige {degats} dégâts !")
cible.subir_degats(degats)
class PokemonPlante(Pokemon):
def __init__(self, nom, niveau=1, pv_max=100, attaque=10):
super().__init__(nom, "Plante", niveau, pv_max, attaque)
def attaquer(self, cible):
"""
Attaque avec ×2 dégâts si la cible est de type Eau.
"""
degats = self.attaque
if cible.type_pokemon == "Eau":
degats = degats * 2
print("C'est super efficace !")
print(f"{self.nom} attaque {cible.nom} et inflige {degats} dégâts !")
cible.subir_degats(degats)
```
**Explications :**
- `super().__init__(...)` appelle le constructeur de `Pokemon` : les sous-classes n'ont pas à réécrire l'initialisation des attributs, elles fixent seulement le type.
- Chaque sous-classe **redéfinit** `attaquer`. Quand on écrit `salameche.attaquer(...)`, Python cherche d'abord la méthode dans `PokemonFeu`, et ne remonte à `Pokemon` que s'il ne la trouve pas.
- Les trois méthodes `attaquer` se ressemblent beaucoup : c'est justement la question de l'exercice 10.
---
### Exercice 9 : isinstance() en pratique
```python
>>> salameche = PokemonFeu("Salamèche", niveau=15, pv_max=70, attaque=12)
>>> isinstance(salameche, PokemonFeu)
True
>>> isinstance(salameche, Pokemon)
True
```
`salameche` est une instance des deux classes, car `PokemonFeu` **hérite** de `Pokemon` : un Pokémon Feu **est un** Pokémon. Il possède tous ses attributs et toutes ses méthodes (`est_ko`, `soigner`...). C'est pour cela qu'on peut le placer dans l'équipe d'un `Dresseur` sans rien changer à cette classe.
```python
def compter_par_type(equipe):
"""
Compte les Pokémon de chaque type.
:param equipe: (list) Liste de Pokémon
:return: (dict) Dictionnaire {type: nombre}
"""
compteur = {}
for pokemon in equipe:
if pokemon.type_pokemon in compteur:
compteur[pokemon.type_pokemon] += 1
else:
compteur[pokemon.type_pokemon] = 1
return compteur
```
---
### Exercice 10 : Refactoring
Il n'y a pas de réponse unique. Éléments de discussion :
- **Avec les sous-classes**, chaque type porte son propre comportement : c'est lisible, et l'on peut donner à un type des particularités qui ne se résument pas à des faiblesses. Mais le code d'`attaquer` est recopié trois fois, et ajouter un type oblige à écrire une nouvelle classe.
- **Avec le dictionnaire `FAIBLESSES`**, toutes les règles sont réunies au même endroit et ajouter une faiblesse se fait en une ligne, sans toucher au code. Il gère aussi naturellement un type faible contre plusieurs autres.
- Pour des **données** (qui bat qui), le dictionnaire est plus adapté. Les sous-classes sont intéressantes quand les types ont des **comportements** vraiment différents. On peut combiner les deux : des sous-classes qui consultent le dictionnaire.
---
Auteurs : Florian Mathieu, Enzo Frémeaux, Timothée Decoster
Licence CC BY-SA