# 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) >>> type("salut") >>> type([1, 2]) ``` 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 `` : 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 Licence Creative Commons
Ce cours est mis à disposition selon les termes de la Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International.