Files
TermNSI/POO/FICHE_REVISION.md
T
2026-10-02 10:31:41 +02:00

248 lines
10 KiB
Markdown

# Fiche de révision : la programmation orientée objet
> Une fiche pour reprendre les bases, et surtout la différence entre une **classe** et un **objet**. Les exemples reprennent le TP Pokémon Arena.
---
## 1. Vous faites de la POO depuis la Première
Bonne nouvelle : la POO n'est pas un monde nouveau. Vous utilisez des objets depuis l'année dernière sans le savoir.
```python
>>> type(3)
<class 'int'>
>>> type("salut")
<class 'str'>
>>> type([1, 2])
<class 'list'>
```
Python vous le dit lui-même : `3` est un objet de la **classe** `int`, `"salut"` un objet de la classe `str`, `[1, 2]` un objet de la classe `list`.
Et quand vous écrivez `ma_liste.append(3)` ou `"salut".upper()`, vous appelez une **méthode** sur un **objet**. Le point entre les deux signifie : « applique cette méthode à cet objet-là ».
En Terminale, la seule nouveauté, c'est que vous allez **écrire vos propres classes**.
---
## 2. Classe ou objet ? La différence en une image
Reprenons l'image du cours : **la classe, c'est le plan d'architecte ; l'objet, c'est la maison construite.** Avec un seul plan, on peut construire toute une rue de maisons. Elles ont la même forme, mais chacune a sa propre couleur de volets, ses propres habitants, et si on repeint l'une, les autres ne changent pas.
Avec les Pokémon :
- la **classe** `Pokemon`, c'est le **formulaire vierge** du Pokédex : il prévoit des cases « nom », « type », « PV », mais il ne contient aucun Pokémon ;
- un **objet**, c'est un **Pokémon précis**, avec ses cases remplies : *ce* Pikachu-là, avec *ses* 80 PV.
| | Classe | Objet (ou instance) |
|:--|:--|:--|
| C'est… | un modèle, un plan | un exemplaire construit à partir du modèle |
| Combien ? | écrite **une seule fois** | créé **autant de fois qu'on veut** |
| Dans le code | `class Pokemon:` | `pikachu = Pokemon("Pikachu", "Electrik", 80)` |
| Nom | commence par une **majuscule** | une variable, en minuscules |
| Contient des valeurs ? | non, elle décrit **quelles** données existeront | oui, **ses propres** valeurs |
Voici une classe très courte :
```python
class Pokemon:
def __init__(self, nom, type_pokemon, pv):
self.nom = nom
self.type_pokemon = type_pokemon
self.pv = pv
def subir_degats(self, degats):
self.pv = self.pv - degats
```
Ce code **ne crée aucun Pokémon**. Il explique seulement comment en fabriquer un. Les objets naissent ici :
```python
pikachu = Pokemon("Pikachu", "Electrik", 80)
autre_pikachu = Pokemon("Pikachu", "Electrik", 80)
```
Deux objets, construits avec le même plan et les mêmes valeurs. Ce sont pourtant **deux Pokémon différents** :
```python
>>> autre_pikachu.subir_degats(30)
>>> pikachu.pv
80
>>> autre_pikachu.pv
50
```
Le premier Pikachu n'a rien senti. Chaque objet a **ses propres attributs**, rangés dans sa propre « boîte ».
!!! tip "À retenir"
**Un objet n'existe que lorsqu'on appelle la classe avec des parenthèses** : `Pokemon(...)`. Chaque appel fabrique un **nouvel** objet. Écrire `class Pokemon:` ne fabrique rien.
---
## 3. Le constructeur et `self`
Que se passe-t-il exactement quand on écrit `pikachu = Pokemon("Pikachu", "Electrik", 80)` ?
1. Python fabrique un **objet vide** de la classe `Pokemon`.
2. Il appelle automatiquement la méthode `__init__`, le **constructeur**, en lui donnant cet objet vide comme **premier paramètre**, `self`.
3. `__init__` remplit l'objet : `self.nom = nom` signifie « range la valeur `nom` dans la case `nom` de **cet objet-là** ».
4. L'objet rempli est rangé dans la variable `pikachu`.
`self` désigne donc toujours **l'objet sur lequel on est en train de travailler**. C'est la même chose pour les autres méthodes :
```python
pikachu.subir_degats(30)
```
est exactement équivalent à :
```python
Pokemon.subir_degats(pikachu, 30)
```
Python fait cette traduction tout seul : l'objet placé **avant le point** devient `self`. C'est pour cela que `self` apparaît dans la définition de la méthode, mais jamais entre les parenthèses à l'appel.
---
## 4. Le vocabulaire
| Mot | Sens | Dans le TP Pokémon |
|:--|:--|:--|
| **Classe** | le modèle | `Pokemon`, `Dresseur`, `Combat` |
| **Objet** ou **instance** | un exemplaire créé à partir de la classe | `pikachu`, `salameche`, `sacha` |
| **Instanciation** | le fait de créer un objet | `Pokemon("Pikachu", "Electrik", 80)` |
| **Attribut** | une donnée rangée dans l'objet | `pikachu.pv`, `pikachu.nom` |
| **Méthode** | une fonction définie dans la classe, qui agit sur un objet | `pikachu.attaquer(salameche)` |
| **Constructeur** | la méthode `__init__`, appelée à la création | remplit `nom`, `type_pokemon`, `pv` |
| **`self`** | l'objet sur lequel la méthode travaille | `pikachu` quand on écrit `pikachu.attaquer(...)` |
---
## 5. Les erreurs classiques
**Oublier `self` dans la définition d'une méthode.**
```python
def __init__(nom): # faux
def __init__(self, nom): # juste
```
Python répond : `TypeError: Pokemon.__init__() takes 1 positional argument but 2 were given`. Il a bien transmis deux choses, l'objet et le nom, mais la méthode n'avait prévu de place que pour une.
**Écrire `nom = nom` au lieu de `self.nom = nom`.**
Sans `self.`, la valeur est rangée dans une variable qui disparaît à la fin de `__init__`, pas dans l'objet. Plus tard, `pikachu.nom` provoque : `AttributeError: 'Pokemon' object has no attribute 'nom'`.
**Appeler une méthode sur la classe au lieu de l'objet.**
```python
Pokemon.subir_degats(10) # faux : quel Pokémon subit les dégâts ?
pikachu.subir_degats(10) # juste
```
C'est exactement la confusion entre classe et objet : la classe est un plan, on ne blesse pas un plan.
**Utiliser `print` au lieu de `return` dans `__repr__`.**
`__repr__` doit **renvoyer** un texte, pas l'afficher. Avec un `print`, Python se plaint : `TypeError: __str__ returned non-string (type NoneType)`.
---
## 6. Un peu d'histoire
!!! info "1967 : des classes pour simuler des navires"
À Oslo, deux chercheurs norvégiens, **Ole-Johan Dahl** et **Kristen Nygaard**, veulent simuler des systèmes réels : des files d'attente, du trafic, des navires dans un port. Ils créent le langage **Simula 67**, qui invente les **classes** et les **objets** : chaque navire du port devient un objet construit sur le modèle « navire ». C'est exactement l'idée de cette fiche, un plan et des exemplaires. Ils ont reçu en 2001 le **prix Turing**, l'équivalent du prix Nobel de l'informatique.
!!! info "Alan Kay et l'expression « orienté objet »"
Dans les années 1970, au centre de recherche de Xerox à Palo Alto, **Alan Kay** et son équipe créent le langage **Smalltalk**, où absolument tout est un objet. Alan Kay raconte que c'est lui qui a inventé l'expression « programmation orientée objet ». Des années plus tard, devant une salle d'informaticiens, il ajoutera avec malice : « J'ai inventé l'expression orienté objet, et je peux vous dire que je ne pensais pas à C++. »
!!! info "Et Python dans tout ça ?"
Python pousse cette idée aussi loin que Smalltalk : en Python, **tout est objet**. Les nombres, les textes, les listes, et même les fonctions et les classes elles-mêmes. C'est pour cela que `type(3)` répond `<class 'int'>` : depuis la Première, vous manipulez des objets.
---
## 7. Pour revoir en vidéo
[Programmation orientée objet - PYTHON - TLE - Spé NSI](https://www.youtube.com/watch?v=yncatRjlEa0&t=50s), par David Latouche (2020).
Regardez de **0:50 à 9:51** : les concepts clés, la déclaration d'une classe et le constructeur, l'instanciation d'un objet, les attributs et les méthodes. La suite (encapsulation, héritage, polymorphisme) dépasse le programme de Terminale.
---
## 8. À vous
!!! question "Exercice 1 : Classe ou objet ?"
Dans le code ci-dessous, indiquez pour chaque nom s'il désigne une **classe**, un **objet**, un **attribut** ou une **méthode** : `Dresseur`, `sacha`, `equipe`, `ajouter`, `pikachu`.
```python
class Dresseur:
def __init__(self, nom):
self.nom = nom
self.equipe = []
def ajouter(self, pokemon):
self.equipe.append(pokemon)
sacha = Dresseur("Sacha")
sacha.ajouter(pikachu)
```
??? success "Correction de l'exercice 1"
- `Dresseur` : une **classe** (mot-clé `class`, majuscule).
- `sacha` : un **objet**, créé par `Dresseur("Sacha")`.
- `equipe` : un **attribut** (`self.equipe`), la liste des Pokémon du dresseur.
- `ajouter` : une **méthode**, définie dans la classe et appelée sur l'objet `sacha`.
- `pikachu` : un **objet**, de la classe `Pokemon`. Ce n'est pas parce qu'il est rangé dans l'équipe de Sacha qu'il devient un `Dresseur`.
!!! question "Exercice 2 : Combien d'objets ?"
Avec la classe `Pokemon` de la partie 2 :
```python
a = Pokemon("Évoli", "Normal", 55)
b = Pokemon("Évoli", "Normal", 55)
c = a
b.subir_degats(10)
c.subir_degats(5)
```
1. Combien d'objets `Pokemon` ont été créés ?
2. Que valent `a.pv`, `b.pv` et `c.pv` ?
??? success "Correction de l'exercice 2"
1. **Deux objets** seulement. Seuls `Pokemon(...)` avec des parenthèses fabriquent un objet, et il y en a deux. `c = a` ne crée rien : c'est un **deuxième nom** pour le même objet que `a`.
2. `a.pv` vaut **50**, `b.pv` vaut **45** et `c.pv` vaut **50**. `b` a subi 10 dégâts. `c` et `a` étant le même Pokémon, les 5 dégâts infligés « à `c` » sont subis par `a`.
!!! question "Exercice 3 : Écrire une classe"
Écrivez une classe `Badge` dont le constructeur reçoit un `nom` et une `ville`, et range ces deux valeurs dans l'objet. Créez ensuite le badge « Roche » de la ville d'Argenta, puis affichez sa ville.
??? success "Correction de l'exercice 3"
```python
class Badge:
def __init__(self, nom, ville):
self.nom = nom
self.ville = ville
badge_roche = Badge("Roche", "Argenta")
print(badge_roche.ville)
```
Points à vérifier : `self` en premier paramètre de `__init__`, `self.nom` et `self.ville` (et pas `nom = nom`), et l'objet créé avec des parenthèses avant d'accéder à son attribut.
---
Auteur : Florian Mathieu
Licence CC BY-SA
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International</a>.