Aller au contenu
M03 · A. Appréhender le paradigme de la POO

L'encapsulation : protéger les données d'un objet

Cacher les attributs sensibles d'un objet et n'y donner accès qu'à travers des méthodes (accesseurs et modificateurs) qui vérifient les règles.

1Situer

Dans l'application d'une banque, n'importe quelle partie du programme peut écrire compte.solde = -5000. Résultat : des soldes négatifs, des dépôts de zéro dirham, et personne ne sait qui a modifié quoi. L'encapsulation règle ce problème : le solde devient privé, et on ne le change qu'en passant par deposer() et retirer(), qui vérifient les montants.

2Comprendre

L'encapsulation : on passe par les méthodes
CODE EXTÉRIEUR solde = -5000 deposer(200) retirer(1000) print(solde) compte 🔒 privé __solde 500 méthodes = portes ✕ +200 ✓ solde insuffisant 700 (lecture seule)

L'objet compte cache son solde dans une zone privée (__solde). De l'extérieur, on ne voit que ses méthodes.

1 / 5

L’encapsulation consiste à cacher l’intérieur d’un objet et à n’exposer que ce qui est utile. On décide qui peut lire et modifier chaque attribut.

Public, protégé, privé

NomVisibilitéAccès depuis l’extérieur
titulairepubliclibre
_titulaireprotégé (convention)possible, mais déconseillé
__soldeprivébloqué : Python renomme l’attribut

Un attribut privé n’est accessible qu’à l’intérieur des méthodes de la classe.

Accesseurs et modificateurs

Pour lire ou modifier un attribut privé, on écrit des méthodes :

  • un accesseur (getter) renvoie la valeur : get_solde() ;
  • un modificateur (setter) change la valeur après vérification : set_solde(valeur).

En Python, la forme la plus élégante est @property : on écrit compte.solde comme un attribut, mais c’est une méthode qui s’exécute.

@property
def solde(self):
    return self.__solde

Sans setter, l’attribut est en lecture seule : compte.solde = 5 déclenche une erreur.

Pourquoi encapsuler ?

  • L’objet reste toujours dans un état valide (pas de solde négatif).
  • On peut changer l’intérieur de la classe sans casser le code qui l’utilise.
  • Les règles métier sont écrites à un seul endroit.
Exemple simple

Le guichet de la banque

Vous ne rentrez pas dans le coffre-fort pour prendre votre argent. Vous passez par le guichet, qui vérifie votre identité et votre solde. Le coffre, c'est l'attribut privé ; le guichet, ce sont les méthodes.

Exemple simple

Le thermostat

On ne règle pas la chaudière à la main : on passe par le thermostat, qui refuse les valeurs absurdes. Un modificateur (setter) fait pareil.

def set_temperature(self, t):
    if 5 <= t <= 30:
        self.__temperature = t
    else:
        print("Valeur refusée")

3Manipuler

Exécutez le code. Dans le panneau « Mémoire », l'attribut privé apparaît avec un cadenas. Essayez ensuite de retirer 1000 DH, puis de déposer -50 DH : les règles sont respectées.
Pas à pas dans le lab ↗Python se charge au premier clic (environ 12 Mo, une seule fois).
Console
Mémoire : objets créés

Exécutez le code : les objets et leurs attributs s'afficheront ici.

4Pratiquer

Exercice 1 · L'âge toujours positif

Écrivez une classe Personne avec un attribut privé __age, un getter get_age() et un setter set_age(age) qui refuse un âge négatif ou supérieur à 120.

Voir le corrigé
class Personne:
    def __init__(self, nom, age):
        self.nom = nom
        self.__age = 0
        self.set_age(age)

    def get_age(self):
        return self.__age

    def set_age(self, age):
        if 0 <= age <= 120:
            self.__age = age
        else:
            print("Âge invalide")

p = Personne("Omar", 30)
p.set_age(-4)          # Âge invalide
print(p.get_age())     # 30

Exercice 2 · Avec @property

Réécrivez la classe Personne en utilisant @property et @age.setter, pour pouvoir écrire p.age = 31.

Voir un indice

Le setter se déclare avec @age.setter juste au-dessus d'une méthode qui porte le même nom age.

Voir le corrigé
class Personne:
    def __init__(self, nom, age):
        self.nom = nom
        self.age = age          # passe par le setter

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, valeur):
        if not 0 <= valeur <= 120:
            raise ValueError("Âge invalide")
        self.__age = valeur

p = Personne("Omar", 30)
p.age = 31
print(p.age)

Exercice 3 · Le name mangling

Que se passe-t-il si vous écrivez print(compte.__solde) en dehors de la classe ? Et print(compte._CompteBancaire__solde) ? Expliquez.

Voir le corrigé
compte.__solde provoque une AttributeError : Python a renommé
l'attribut en _CompteBancaire__solde (name mangling).
compte._CompteBancaire__solde fonctionne, mais c'est un contournement
à ne jamais utiliser : en Python, le privé est une protection
contre les erreurs, pas un verrou de sécurité.

5Vérifier

1. Comment déclare-t-on un attribut privé en Python ?
2. À quoi sert un setter (modificateur) ?
3. Que signifie un attribut qui commence par un seul tiret bas, comme _nom ?