Comment encapsuler des noms d’attributs/fonction dans une classe en Python

Vous voulez encapsuler des données “privées” sur les instances d’une classe, mais vous êtes préoccupé par le manque de contrôle d’accès de Python.

Plutôt que de se fier aux caractéristiques du langage pour encapsuler les données, les programmeurs Python doivent observer certaines conventions de nommage concernant l’utilisation prévue des données et des méthodes.

La première convention est que tout nom commençant par un seul trait de soulignement principal (_) doit toujours être considéré comme une mise en œuvre interne. Par exemple:

class A:
    def __init__(self):
        self._interne = 0    # Un attribut interne
        self.public = 1       # Un attribut public

    def methode_publique(self):
        '''
        Une méthode publique
        '''
        ...

    def _method_interne(self):
        ...

Python n’empêche pas vraiment quelqu’un d’accéder aux noms internes. Cependant, faire cela est considéré comme impoli et peut entraîner la fragilité du code.

Il convient également de noter que l’utilisation du trait de soulignement principal est également utilisée pour les noms de modules et les fonctions au niveau des modules.

Par exemple, si vous voyez un nom de module qui commence par un trait de soulignement (par exemple, _socket), c’est une implémentation interne. De même, les fonctions de niveau module telles que sys._getframe() ne doivent être utilisées qu’avec une grande prudence.

Vous pouvez également rencontrer l’utilisation de deux traits de soulignement principaux (__) sur les noms dans les définitions de classe. Par exemple:

class B:
    def __init__(self):
        self.__private = 0
    def __private_method(self):
        ...
    def methode_publique(self):
        ...
        self.__private_method()
        ...

L’utilisation de traits de soulignement doubles fait que le nom est mélangé à quelque chose d’autre. Plus précisément, les attributs privés de la classe précédente sont renommés respectivement _B__private et _B__private_method.

À ce stade, vous vous demandez peut-être à quoi sert un tel changement de nom. La réponse est l’héritage : ces attributs ne peuvent pas être remplacés par l’héritage. Par exemple:

class C(B):
    def __init__(self):
        super().__init__()
        self.__private = 1      # Ne remplace pas B.__private
    # Ne remplace pas B.__private_method()
    def __private_method(self):
        ...

Ici, les noms privés __private et __method_private sont renommés en _C__private et _C__method_private, qui sont différents des noms mutilés de la classe de base B.

Le fait qu’il existe deux conventions différentes (trait de soulignement simple contre trait de soulignement double) pour les attributs “privés” conduit à la question évidente du style que vous devez utiliser.

Pour la plupart des codes, vous devriez probablement faire en sorte que vos noms non publics commencent par un simple soulignement.

Si, cependant, vous savez que votre code impliquera l’héritage, et qu’il y a des attributs internes qui devraient être cachés des classes filles, utilisez plutôt le double soulignement.

Il faut également noter que parfois vous pouvez vouloir définir une variable qui est en conflit avec le nom d’un mot réservé. Pour cela, vous devez utiliser un seul trait de soulignement. Par exemple:

lambda_ = 2.0 # Mise du carcatère _ à la fin pour éviter tout conflit avec le mot-clé lambda

La raison pour laquelle on n’utilise pas de trait de soulignement principal ici est qu’il évite la confusion au sujet de l’utilisation prévue (c.-à-d. que l’utilisation d’un trait de soulignement principal pourrait être interprétée comme un moyen d’éviter une collision de noms plutôt que comme une indication que la valeur est privée).

L’utilisation d’un seul trait de soulignement résout ce problème.

LAISSER UN COMMENTAIRE

Please enter your comment!
Please enter your name here