Chapitre 23 : Classes et Objets
class, __init__, self
1. Quoi : La Programmation Orientée Objet (POO)
La Programmation Orientée Objet est un paradigme de programmation qui repose sur le concept d'"objets". Un objet est une entité qui regroupe des données (appelées attributs) et des comportements (appelées méthodes).
- Une Classe est un plan ou un modèle pour créer des objets. Elle définit les attributs et les méthodes que tous les objets de cette classe auront.
- Un Objet (ou une instance) est une création concrète à partir d'une classe. Vous pouvez créer de multiples objets à partir d'une seule classe, chacun avec ses propres valeurs d'attributs.
Imaginez que la classe Voiture est le plan de construction. Les objets ma_voiture_rouge et la_voiture_de_mon_voisin sont des voitures réelles construites à partir de ce plan.
2. Pourquoi : Modéliser le monde réel
La POO est extrêmement puissante pour organiser des programmes complexes, car elle permet de modéliser des concepts du monde réel.
- Encapsulation : Regrouper les données et les comportements qui leur sont liés au sein d'un même objet. Cela rend le code plus organisé et plus facile à gérer.
- Abstraction : Cacher les détails complexes de l'implémentation et n'exposer qu'une interface simple pour interagir avec l'objet.
- Héritage : Créer de nouvelles classes basées sur des classes existantes pour réutiliser du code et créer des hiérarchies (ex: une classe
Chatet une classeChienpeuvent hériter d'une classeAnimal). - Polymorphisme : Permettre à des objets de différentes classes de répondre au même message (appel de méthode) de manière spécifique à leur type.
3. Comment : Définir une Classe en Python
A. Syntaxe de base
On définit une classe avec le mot-clé class, suivi du nom de la classe (par convention, en CamelCase).
class Dog:
# Le code de la classe est indenté
pass # 'pass' est un placeholder pour indiquer un bloc vide
B. Le Constructeur : __init__()
La méthode __init__() est une méthode spéciale appelée "constructeur". Elle est exécutée automatiquement chaque fois qu'un nouvel objet de la classe est créé. C'est l'endroit idéal pour initialiser les attributs de l'objet.
- Le premier paramètre de chaque méthode d'instance est toujours
self.selfreprésente l'objet lui-même. C'est à traversselfque vous pouvez accéder aux attributs et méthodes de l'objet.
class Dog:
# Le constructeur
def __init__(self, name, age):
# On crée les attributs de l'instance 'self'
self.name = name
self.age = age
print(f"A new dog named {self.name} has been created!")
# Création de deux objets (instances) de la classe Dog
dog1 = Dog("Buddy", 3)
dog2 = Dog("Lucy", 5)
# Chaque objet a ses propres attributs
print(f"{dog1.name} is {dog1.age} years old.") # Buddy is 3 years old.
print(f"{dog2.name} is {dog2.age} years old.") # Lucy is 5 years old.
C. Les Méthodes d'Instance
Les méthodes sont des fonctions définies à l'intérieur d'une classe. Elles représentent les comportements de l'objet. Elles prennent toujours self comme premier argument pour pouvoir accéder aux attributs de l'instance.
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
# Une méthode d'instance
def bark(self):
print(f"{self.name} says: Woof!")
# Une autre méthode d'instance qui utilise les attributs
def get_human_years(self):
return self.age * 7
# Création d'un objet
my_dog = Dog("Rex", 4)
# Appel des méthodes de l'objet
my_dog.bark() # Rex says: Woof!
human_age = my_dog.get_human_years()
print(f"In human years, {my_dog.name} is {human_age} years old.")
D. Attributs de Classe
Un attribut de classe est une variable qui est partagée par toutes les instances de la classe. On le définit directement sous la déclaration de la classe, en dehors de toute méthode.
class Dog:
# Attribut de classe, partagé par tous les chiens
species = "Canis familiaris"
def __init__(self, name):
self.name = name # Attribut d'instance
dog1 = Dog("Buddy")
dog2 = Dog("Lucy")
# On peut y accéder via la classe ou l'instance
print(Dog.species) # Canis familiaris
print(dog1.species) # Canis familiaris
print(dog2.species) # Canis familiaris
4. Exemple complet : un compte bancaire
class BankAccount:
# Le constructeur initialise le compte avec un nom de titulaire et un solde initial
def __init__(self, owner_name, initial_balance=0):
self.owner_name = owner_name
self.balance = initial_balance
print(f"Account for {self.owner_name} created with balance: ${self.balance}")
# Méthode pour déposer de l'argent
def deposit(self, amount):
if amount > 0:
self.balance += amount
print(f"Deposited ${amount}. New balance: ${self.balance}")
else:
print("Deposit amount must be positive.")
# Méthode pour retirer de l'argent
def withdraw(self, amount):
if 0 < amount <= self.balance:
self.balance -= amount
print(f"Withdrew ${amount}. New balance: ${self.balance}")
else:
print("Invalid withdrawal amount or insufficient funds.")
# Méthode pour afficher le solde
def get_balance(self):
print(f"Current balance for {self.owner_name}: ${self.balance}")
# Utilisation de la classe
account1 = BankAccount("Alice", 500)
account1.deposit(100)
account1.withdraw(50)
account1.withdraw(600) # Tentative de retrait invalide
account1.get_balance()
Exercices :
Exercice 23 - Modélisation d'une Voiture
Objectif
Cet exercice a pour but de vous faire créer votre première classe, Car, pour modéliser un objet simple avec ses attributs (données) et ses méthodes (comportements).
Contexte
Vous allez créer une classe Car qui représente une voiture. Une voiture a une marque, un modèle, une année, et un kilométrage. Elle peut également rouler (ce qui augmente son kilométrage) et afficher ses informations.
Énoncé
-
Créez un nouveau fichier Python nommé
car_model.py. -
Définissez la classe
Car.- Par convention, les noms de classe utilisent le
CamelCase.
- Par convention, les noms de classe utilisent le
-
Écrivez le constructeur
__init__:- Il doit accepter trois arguments (en plus de
self) :make(la marque),model(le modèle), etyear(l'année). - À l'intérieur du constructeur, initialisez les attributs d'instance suivants :
self.makeself.modelself.yearself.odometer_reading: initialisez cet attribut à0. Il représentera le kilométrage de la voiture.
- Il doit accepter trois arguments (en plus de
-
Créez une méthode
get_descriptive_name:- Cette méthode ne prend pas d'autres arguments que
self. - Elle doit retourner une chaîne de caractères formatée décrivant la voiture, par exemple :
"2023 Ford Mustang".
- Cette méthode ne prend pas d'autres arguments que
-
Créez une méthode
read_odometer:- Cette méthode doit afficher le kilométrage de la voiture de manière claire, par exemple :
"This car has 0 miles on it.".
- Cette méthode doit afficher le kilométrage de la voiture de manière claire, par exemple :
-
Créez une méthode
drive:- Cette méthode doit accepter un argument
miles(le nombre de kilomètres parcourus). - Elle doit vérifier que
milesest un nombre positif. - Si c'est le cas, elle ajoute ce nombre au
self.odometer_reading. - Sinon, elle affiche un message d'erreur :
"You can't drive negative miles!".
- Cette méthode doit accepter un argument
-
Testez votre classe :
- Créez une instance de votre classe
Car. - Appelez
get_descriptive_nameet affichez le résultat. - Appelez
read_odometer. - Appelez la méthode
driveavec une valeur positive (ex: 100) et appelez à nouveauread_odometerpour voir le changement. - Appelez la méthode
driveavec une valeur négative pour tester la gestion de l'erreur.
- Créez une instance de votre classe
Résultat Attendu
2023 Ford Mustang
This car has 0 miles on it.
This car has 100 miles on it.
You can't drive negative miles!
Cliquez ici pour voir un exemple de code de solution
# car_model.py
class Car:
"""A simple attempt to represent a car."""
def __init__(self, make, model, year):
"""Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = f"{self.year} {self.make} {self.model}"
return long_name.title()
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print(f"This car has {self.odometer_reading} miles on it.")
def drive(self, miles):
"""Increase the odometer reading by the given amount."""
if miles >= 0:
self.odometer_reading += miles
else:
print("You can't drive negative miles!")
# --- Testing the class ---
# Create an instance of the Car class
my_new_car = Car('ford', 'mustang', 2023)
# Print the descriptive name
print(my_new_car.get_descriptive_name())
# Read the initial odometer reading
my_new_car.read_odometer()
# Drive the car
my_new_car.drive(100)
my_new_car.read_odometer()
# Attempt to drive negative miles
my_new_car.drive(-50)