Attribut privé et propriété

21 mars 2024

python logo

J'ai répondu à deux questions très intéressantes sur Docstring.

  1. Pourquoi utiliser un setter avec le property ?
  2. Pourquoi utiliser un underscore simple et non un double ( pour rendre un attribut privé) ?

L'utilité des attributs privés

L'underscore permet de signaler aux autres développeurs qu'il ne faut pas accéder directement à l'attribut depuis l’extérieur de la classe.

En utilisant un unserscore on rend l’attribut privé. Mais il s'agit uniquement d'une convention. En effet, celui qui ne veut pas respecter la convention peut très bien accéder à l'attribut en dehors de la classe.

Exemple avec un exercice très intéressant sur le sujet sur la plateforme Docstring :

class Compte:
    def __init__(self, nom, numero, balance):
        self.nom = nom
        self._numero = numero
        self.balance = balance

    @property
    def numero(self):
        return self._numero

    @numero.setter
    def numero(self, numero):
        raise AttributeError("On ne change pas le numéro de compte !")

john = Compte(nom="John Smith", numero="123456", balance=20000)

print(john._numero)
# 123456

Le double underscore est différent. Un attribut ou une méthode qui les utilise le mécanisme de name mangling. Python modifie le nom de l'attribut en y ajoutant le nom de la classe.

Par exemple, si vous avez une classe MaClasse avec un attribut __mon_attribut, Python le renomme en _MaClasse__mon_attribut.

Et là ce n'est pas impossible, mais c'est plus compliqué d'accéder à l'attribut en dehors de la classe :

class Compte:
    def __init__(self, nom, numero, balance):
        self.nom = nom
        self.__numero = numero
        self.balance = balance

    @property
    def numero(self):
        return self._numero

    @numero.setter
    def numero(self, numero):
        raise AttributeError("On ne change pas de numéro de compte")

john = Compte(nom="John Smith", numero="123456", balance=20000)
print(john.__numero)
# AttributeError

Avec le name mangling, pour accéder à l'attribut en dehors de la classe il faudrait faire :

print(john._Compte__numero)
# 123456

Il est préférable de suivre les bonnes pratiques de conception en Python en évitant d'accéder directement aux attributs privés, qu'ils soient marqués par un ou deux traits de soulignement.

Property et Setter

Les propriétés permettent de définir des méthodes pour accéder à un attribut comme s'il s'agissait d'un attribut.

En utilisant la décoration @property pour une méthode, celle-ci peut être appelée comme un attribut.

class Compte:
    def __init__(self, nom, numero, balance):
        self.nom = nom
        self._numero = numero
        self.balance = balance

    @property
    def numero(self):
        return self._numero

    @numero.setter
    def numero(self, numero):
        raise AttributeError("On ne change pas le numéro de compte !")

john = Compte(nom="John Smith", numero="123456", balance=20000)

print(john.numero)
# En faisant ça vous appeler la méthode def numero, non pas self._numero

Les setters, quant à eux permettent de définir des méthodes pour modifier la valeur d'un attribut, ce qui offre un contrôle supplémentaire sur la façon dont les attributs sont modifiés.

Python permet de définir une méthode qui sera appelée lorsqu'un utilisateur tente de modifier la valeur de l'attribut correspondant.

john.numero = 12345789
# raise AttributeError("On ne change pas le numéro de compte !")

Prenons un autre exemple :

class Personne:
    def __init__(self, nom, age):
        self.nom = nom
        self._age = age

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

    @age.setter
    def age(self, value):
        if value < 0:
            raise ValueError("L'âge ne peut pas être négatif")
        else:
            self._age = value

# Création de l'instance
personne = Personne("Patrick", 30)
# Modification avec le setter
personne.age = -5
# Lève ValueError: L'âge ne peut pas être négatif

Pour terminer, en lien avec tout ce que l'on vient de voir, nous allons évoquer l'encapsulation.

L'encapsulation est un concept en programmation orientée objet qui implique la restriction de l'accès direct aux attributs et méthodes d'un objet. Cela signifie que les détails internes d'un objet sont cachés et ne peuvent être modifiés que par des méthodes spécifiques de la classe. De cette manière, on peut assurer l'intégrité des données et réduire les effets de bord indésirables en limitant les interactions directes avec les attributs de l'objet.

Retour