Pourquoi la POO ?
Imaginez que vous développez un jeu vidéo avec des personnages. Chaque personnage a :
- Des données : nom, points de vie, force, équipement...
- Des comportements : attaquer, se défendre, soigner, mourir...
Sans POO, il faudrait gérer tout ça avec des dictionnaires et des fonctions séparées :
# Sans POO : dict + fonctions éparpillées
personnage = {"nom": "Aragorn", "pv": 100, "force": 20}
def attaquer(attaquant, cible):
degats = attaquant["force"]
cible["pv"] -= degats
legolas = {"nom": "Legolas", "pv": 80, "force": 15}
attaquer(personnage, legolas)
print(legolas)Problèmes :
- Les données et les fonctions sont éparpillées.
- N'importe qui peut modifier directement les PV (
personnage["pv"] = 9999). - Pas de réutilisation : si on veut un nouveau type de personnage, on recopie tout.
- Pas de contrat : rien ne garantit qu'un « personnage » a bien les clés
pvetforce.
Avec la POO, on regroupe données + comportements dans une classe :
class Personnage:
def __init__(self, nom, pv, force):
self.nom = nom
self.pv = pv
self.force = force
def attaquer(self, cible):
cible.pv -= self.force
# Création de personnages
aragorn = Personnage("Aragorn", 100, 20)
legolas = Personnage("Legolas", 80, 15)
# Utilisation
aragorn.attaquer(legolas)
print(f"{legolas.nom} a maintenant {legolas.pv} PV")Plus propre, plus sûr, plus extensible.
Vocabulaire essentiel
| Terme | Définition |
|---|---|
| Classe | Le moule — définit le type d'objet (ses attributs, ses méthodes). |
| Instance | Un objet concret créé à partir de la classe. |
| Attribut | Une donnée stockée dans une instance ou une classe. |
| Méthode | Une fonction définie dans une classe, appelée sur une instance. |
self |
Référence à l'instance courante dans les méthodes. |
| Constructeur | La méthode spéciale __init__ qui initialise un nouvel objet. |
Analogie
- Une classe = le plan d'une maison.
- Une instance = une maison construite selon ce plan.
- Les attributs = couleur de la façade, nombre de pièces (propres à chaque maison).
- Les méthodes = actions possibles (ouvrir la porte, allumer la lumière).
Définir une classe
class NomDeClasse:
# corps de la classe
...Convention PEP 8 : nom de classe en PascalCase (première lettre de chaque mot en majuscule, sans underscore).
class Chien:
pass # classe vide pour l'instant
# Créer des instances
rex = Chien()
medor = Chien()
print(rex)
print(type(rex))
print(rex is medor) # False : deux instances distinctesLes parenthèses () à l'appel Chien() instancient la classe (créent un nouvel objet).
Les attributs d'instance
Un attribut d'instance est une donnée propre à chaque objet. On les ajoute avec instance.attribut = valeur.
class Chien:
pass
rex = Chien()
rex.nom = "Rex"
rex.age = 3
rex.race = "Berger allemand"
medor = Chien()
medor.nom = "Médor"
medor.age = 7
print(f"{rex.nom}, {rex.age} ans, {rex.race}")
print(f"{medor.nom}, {medor.age} ans")Chaque instance a ses propres attributs — rex.nom et medor.nom sont indépendants.
Limite de cette approche
Écrire rex.nom = ...; rex.age = ... à chaque création est fastidieux et risqué : on peut oublier un attribut, ou faire une faute de frappe.
C'est le rôle du constructeur __init__.
Le constructeur __init__
__init__ (prononcé « dunder init », pour double underscore init) est une méthode spéciale appelée automatiquement à la création d'une instance. Elle sert à initialiser les attributs.
class Chien:
def __init__(self, nom, age, race="inconnue"):
self.nom = nom
self.age = age
self.race = race
# Création — les arguments passent au __init__
rex = Chien("Rex", 3, "Berger allemand")
medor = Chien("Médor", 7) # race prend sa valeur par défaut
print(f"{rex.nom}, {rex.age} ans, {rex.race}")
print(f"{medor.nom}, {medor.age} ans, {medor.race}")Anatomie
def __init__(self, nom, age, race="inconnue"):
│ │ │ │
│ │ │ valeur par défaut (classique)
│ │ paramètres passés à l'appel Chien(...)
│ référence à l'instance courante
méthode spéciale PythonPoints à noter :
__init__ne se return pas une valeur : Python renvoie l'instance automatiquement.- Les paramètres après
selfsont ceux qu'on passe à l'appel :Chien("Rex", 3). self.nom = nomstocke le paramètre dans l'attribut.