Review cours Terminale NSI — POO, SQL, Sécurité, Soc, Calculabilité, Réseau
This commit is contained in:
@@ -248,6 +248,88 @@ Ces méthodes sont appelées des accesseurs et modificateurs. Elles sont optionn
|
||||
|
||||
-----------
|
||||
|
||||
## L'héritage
|
||||
|
||||
Jusqu'ici, nous avons créé des classes indépendantes les unes des autres. Mais en POO, il est possible de créer une classe à partir d'une autre classe existante : c'est le principe de l'**héritage**.
|
||||
|
||||
L'idée est simple : une classe **enfant** hérite de tous les attributs et méthodes d'une classe **parent**, et peut en ajouter de nouveaux ou en modifier certains.
|
||||
|
||||
> L'héritage modélise une relation **"est-un"** : un `EtudiantBoursier` **est un** `Etudiant`. À ne pas confondre avec la composition vue dans le TP Pokémon, qui modélise une relation **"a-un"** : un `Dresseur` **a des** `Pokemon`.
|
||||
|
||||
### Syntaxe de base
|
||||
|
||||
Supposons que l'on veuille créer un `EtudiantBoursier` qui est un `Etudiant` avec une bourse mensuelle en plus.
|
||||
|
||||
```python
|
||||
class EtudiantBoursier(Etudiant):
|
||||
def __init__(self, nom_etu, prenom_etu, spe1_etu, age_etu, bourse_mensuelle):
|
||||
super().__init__(nom_etu, prenom_etu, spe1_etu, age_etu)
|
||||
self.bourse = bourse_mensuelle
|
||||
```
|
||||
|
||||
Plusieurs choses à noter :
|
||||
|
||||
- `class EtudiantBoursier(Etudiant)` : on indique entre parenthèses la classe parent dont on hérite.
|
||||
- `super().__init__(...)` : on appelle le constructeur de la classe parent pour initialiser les attributs déjà définis. Cela évite de tout réécrire.
|
||||
- On ajoute ensuite les attributs propres à l'enfant (`self.bourse`).
|
||||
|
||||
```python
|
||||
>>> eb = EtudiantBoursier('Martin', 'Léa', 'NSI', 17, 250)
|
||||
>>> eb.nom
|
||||
'Martin'
|
||||
>>> eb.bourse
|
||||
250
|
||||
>>> eb.peut_avoir_son_permis
|
||||
False
|
||||
```
|
||||
|
||||
L'objet `eb` a accès à tous les attributs de `Etudiant` **et** à `bourse`.
|
||||
|
||||
### Surcharge de méthode
|
||||
|
||||
Un `EtudiantBoursier` peut avoir besoin d'une méthode `__repr__` différente de celle de `Etudiant`. On peut alors **surcharger** (redéfinir) la méthode dans la classe enfant :
|
||||
|
||||
```python
|
||||
class EtudiantBoursier(Etudiant):
|
||||
def __init__(self, nom_etu, prenom_etu, spe1_etu, age_etu, bourse_mensuelle):
|
||||
super().__init__(nom_etu, prenom_etu, spe1_etu, age_etu)
|
||||
self.bourse = bourse_mensuelle
|
||||
|
||||
def __repr__(self):
|
||||
return super().__repr__() + f' (boursier : {self.bourse}€/mois)'
|
||||
```
|
||||
|
||||
```python
|
||||
>>> eb = EtudiantBoursier('Martin', 'Léa', 'NSI', 17, 250)
|
||||
>>> eb
|
||||
Martin Léa (boursier : 250€/mois)
|
||||
```
|
||||
|
||||
Ici `super().__repr__()` appelle la version de la classe parent pour ne pas dupliquer le code.
|
||||
|
||||
### isinstance()
|
||||
|
||||
La fonction native `isinstance()` permet de vérifier si un objet est une instance d'une classe donnée — y compris via l'héritage :
|
||||
|
||||
```python
|
||||
>>> eb = EtudiantBoursier('Martin', 'Léa', 'NSI', 17, 250)
|
||||
>>> isinstance(eb, EtudiantBoursier)
|
||||
True
|
||||
>>> isinstance(eb, Etudiant)
|
||||
True
|
||||
```
|
||||
|
||||
`eb` est à la fois un `EtudiantBoursier` ET un `Etudiant`. C'est la conséquence directe de l'héritage.
|
||||
|
||||
### Exercices
|
||||
|
||||
1. Créez une classe `EtudiantInternational` qui hérite de `Etudiant` et possède un attribut supplémentaire `pays_origine`.
|
||||
2. Surchargez `__repr__` pour afficher le pays entre parenthèses.
|
||||
3. Créez une fonction `liste_internationaux(etudiants)` qui prend une liste d'`Etudiant` et renvoie uniquement les `EtudiantInternational`. Utilisez `isinstance()`.
|
||||
4. Que se passe-t-il si on appelle `anniversaire()` sur un `EtudiantBoursier` ? Pourquoi ?
|
||||
|
||||
-----------
|
||||
|
||||
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
@@ -398,14 +398,107 @@ Modifiez la classe `Pokemon` pour qu'un Pokémon possède une liste de capacité
|
||||
|
||||
---
|
||||
|
||||
## Partie 5 : Héritage — Spécialiser les Pokémon
|
||||
|
||||
> **Prérequis** : avoir vu le cours sur l'héritage.
|
||||
|
||||
Jusqu'ici, tous les Pokémon utilisent la même méthode `attaquer`. Mais en vrai, un Pokémon Feu n'attaque pas comme un Pokémon Eau. Plutôt que de gérer ça avec un dictionnaire de faiblesses dans `attaquer`, on peut utiliser l'**héritage** pour créer des sous-classes spécialisées.
|
||||
|
||||
---
|
||||
|
||||
### Exercice 8 : Sous-classes par type
|
||||
|
||||
Créez trois sous-classes qui héritent de `Pokemon` :
|
||||
|
||||
- `PokemonFeu` : inflige ×2 dégâts aux Pokémon Plante
|
||||
- `PokemonEau` : inflige ×2 dégâts aux Pokémon Feu
|
||||
- `PokemonPlante` : inflige ×2 dégâts aux Pokémon Eau
|
||||
|
||||
Chaque sous-classe doit :
|
||||
1. Hériter de `Pokemon` via `class PokemonFeu(Pokemon):`
|
||||
2. Appeler `super().__init__(...)` dans son constructeur en fixant `type_pokemon` automatiquement
|
||||
3. Surcharger la méthode `attaquer` pour appliquer le bonus de dégâts
|
||||
|
||||
```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.
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
```
|
||||
|
||||
**Tests :**
|
||||
```python
|
||||
>>> salameche = PokemonFeu("Salamèche", niveau=15, pv_max=70, attaque=12)
|
||||
>>> bulbizarre = PokemonPlante("Bulbizarre", niveau=15, pv_max=75, attaque=10)
|
||||
>>> salameche.attaquer(bulbizarre)
|
||||
C'est super efficace !
|
||||
Salamèche attaque Bulbizarre et inflige 24 dégâts !
|
||||
>>> bulbizarre.attaquer(salameche)
|
||||
Bulbizarre attaque Salamèche et inflige 10 dégâts !
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Exercice 9 : isinstance() en pratique
|
||||
|
||||
1. Vérifiez que `salameche` est à la fois une instance de `PokemonFeu` **et** de `Pokemon`. Expliquez pourquoi.
|
||||
2. Écrivez une fonction `compter_par_type(equipe)` qui prend une liste de Pokémon et renvoie un dictionnaire `{type: nombre}`.
|
||||
|
||||
```python
|
||||
>>> equipe = [PokemonFeu("Dracaufeu"), PokemonEau("Tortank"), PokemonFeu("Sulfura"), PokemonPlante("Florizarre")]
|
||||
>>> compter_par_type(equipe)
|
||||
{'Feu': 2, 'Eau': 1, 'Plante': 1}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Exercice 10 : Refactoring
|
||||
|
||||
Relisez le dictionnaire `FAIBLESSES` de l'exercice 3. Maintenant que vous avez des sous-classes, ce dictionnaire est-il encore utile ? Quelle approche est plus lisible selon vous ? Discutez.
|
||||
|
||||
---
|
||||
|
||||
## Résumé des classes
|
||||
|
||||
| Classe | Attributs | Méthodes principales |
|
||||
|--------|-----------|----------------------|
|
||||
| `Pokemon` | nom, type, niveau, pv, attaque | attaquer(), subir_degats(), est_ko() |
|
||||
| `Dresseur` | nom, equipe | ajouter_pokemon(), tous_ko() |
|
||||
| `Combat` | dresseur1, dresseur2, tour | lancer_combat() |
|
||||
| `CentrePokemon` | ville | soigner_equipe() |
|
||||
| Classe | Hérite de | Attributs supplémentaires | Méthodes modifiées |
|
||||
|--------|-----------|---------------------------|--------------------|
|
||||
| `Pokemon` | — | nom, type, niveau, pv, attaque | attaquer(), subir_degats(), est_ko() |
|
||||
| `PokemonFeu` | `Pokemon` | — | attaquer() |
|
||||
| `PokemonEau` | `Pokemon` | — | attaquer() |
|
||||
| `PokemonPlante` | `Pokemon` | — | attaquer() |
|
||||
| `Dresseur` | — | nom, equipe | ajouter_pokemon(), tous_ko() |
|
||||
| `Combat` | — | dresseur1, dresseur2, tour | lancer_combat() |
|
||||
| `CentrePokemon` | — | ville | soigner_equipe() |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user