Introduction aux classes en Python
Python est un langage de programmation orienté objet. Une classe regropue des entités partageant des caractéristiques communes, définies par des attributs (variables) et des méthodes (fonctions). Par exemple, une classe Voiture pourrait inclure des attributs comme marque et prix. Si l'on souhaite afficher ces informations pour plusieurs véhicules, l'utilisation d'une fonction permet de réutiliser le code efficacement.
Implémentation avec des fonctions versus classes
Considérons une fonction pour afficher les détails d'une voiture :
def afficher_info_voiture(marque, prix):
print("Détails de la voiture : marque:%s, prix:%d" % (marque, prix))
afficher_info_voiture("BMW", 250000)
afficher_info_voiture("Ford", 15000)
En utilisant une classe, on encapsule les données et les comportements :
class Voiture:
def __init__(self, marque, prix):
self.marque = marque
self.prix = prix
def afficher_details(self):
print("Détails de la voiture : marque:%s, prix:%d" % (self.marque, self.prix))
vehicule1 = Voiture("BMW", 500000)
vehicule2 = Voiture("Ford", 25000)
vehicule1.afficher_details()
vehicule2.afficher_details()
Les méthodes de classe et le mot-clé self
Le paramètre self dans les méthodes représente l'instance de l'objet. Lorsqu'on appelle une méthode sur un objet, Python passe automatiquement cet objet comme premier argument. Ainsi, self.marque et self.prix accèdent aux attributs spécifiques à l'instance.
L'initialisation se fait via la méthode __init__, qui est appelée automatiquement lors de la création d'un objet. Elle assigne les valeurs initiales aux attributs.
Variables et méthodes privées en Python
Pour rendre un attribut ou une méthode privé, on préfixe son nom avec deux underscores (__). Python utilise la technique du name mangling pour transformer le nom interne, le rendant inaccessible directement depuis l'extérieur de la classe.
Exemple :
class Exemple:
def __init__(self):
self.__donnees = []
def ajouter(self, element):
self.__donnees.append(element)
def afficher(self):
print(self.__donnees)
obj = Exemple()
# print(obj.__donnees) # Provoque une AttributeError
obj.ajouter("test")
obj.afficher()
Conventions de nommage avec underscores
- Les noms commençant par un seul underscore (
_attribut) sont considérés comme protégés, accessibles uniquement dans la classe et ses sous-classes. - Les noms avec deux underscores (
__attribut) sont privés, réservés à la classe elle-même. - Les noms entourés de double underscores (
__methode__) sont des méthodes spéciales de Python, comme__init__.
Exemple illustrant les noms privés :
class Parent:
def __init__(self):
self.__secret = "confidentiel"
class Enfant(Parent):
def acceder(self):
# print(self.__secret) # Ne fonctionne pas
pass
instance = Enfant()
print(instance._Parent__secret) # Accès via le nom manglé
Caractéristiques des classes : encapsulation, héritage, polymorphisme
Encapsulation
L'encapsulation consiste à regrouper données et méthodes au sein d'une classe, contrôlant l'accès via des interfaces publiques. Cela évite les modifications non autorisées et améliore la modularité.
Exemple :
class Animal:
def __init__(self, nom, espece):
self.nom = nom
self.espece = espece
self.energie = 100
def manger(self):
self.energie += 10
print(f"{self.nom} mange.")
def afficher_etat(self):
print(f"{self.nom} a {self.energie} d'énergie.")
chat = Animal("Felix", "chat")
chat.manger()
chat.afficher_etat()
Héritage
L'héritage permet à une sous-classe de réutiliser les attributs et méthodes d'une classe parente. On utilise super() pour appeler le constructeur parent.
Exemple d'héritage simple :
class Personne:
def __init__(self, nom, age):
self.nom = nom
self.age = age
class Etudiant(Personne):
def __init__(self, nom, age, note):
super().__init__(nom, age)
self.note = note
etudiant = Etudiant("Alice", 20, 15)
print(etudiant.nom, etudiant.age, etudiant.note)
En cas d'héritage multiple, l'ordre de résolution est défini par la méthode MRO (Method Resolution Order). Python utilise l'algorithme C3 pour déterminer cet ordre.
Polymorphisme
Le polymorphisme signifie qu'une méthode peut se comporter différemment selon le type de l'objet. Par exemple, différentes classes peuvent implémenter une même méthode avec des logiques spécifiques.
Exemple :
class Forme:
def aire(self):
pass
class Cercle(Forme):
def __init__(self, rayon):
self.rayon = rayon
def aire(self):
return 3.14 * self.rayon ** 2
class Rectangle(Forme):
def __init__(self, largeur, hauteur):
self.largeur = largeur
self.hauteur = hauteur
def aire(self):
return self.largeur * self.hauteur
def calculer_aire(forme):
print("Aire:", forme.aire())
cercle = Cercle(5)
rectangle = Rectangle(4, 6)
calculer_aire(cercle)
calculer_aire(rectangle)
Ici, la fonction calculer_aire appelle la méthode aire appropriée en fonction du type de l'objet passé.