web-dev-qa-db-fra.com

Classe (privée) (implémentation) dans Python

Je code un petit module Python composé de deux parties:

  • certaines fonctions définissant une interface publique,
  • une classe d'implémentation utilisée par les fonctions ci-dessus, mais qui n'a pas de sens en dehors du module.

Au début, j'ai décidé de "masquer" cette classe d'implémentation en la définissant à l'intérieur de la fonction l'utilisant, mais cela entrave la lisibilité et ne peut pas être utilisé si plusieurs fonctions réutilisent la même classe.

Donc, en plus des commentaires et des docstrings, existe-t-il un mécanisme pour marquer une classe comme "privée" ou "interne"? Je connais le mécanisme de soulignement, mais si je comprends bien, il ne s'applique qu'aux variables, aux fonctions et aux noms de méthodes.

92
oparisy

Utilisez un seul préfixe de soulignement:

class _Internal:
    ...

Il s'agit de la convention officielle Python pour les symboles "internes"; "from module import *" n'importe pas les objets avec préfixe de soulignement).

Edit: Référence à la convention de soulignement unique

148
Ferdinand Beyer

En bref:

  1. Vous ne pouvez pas appliquer la confidentialité . Il n'y a pas de classes/méthodes/fonctions privées en Python. Du moins, pas de confidentialité stricte comme dans d'autres langages, comme Java.

  2. Vous ne pouvez indiquer/suggérer que la confidentialité . Cela suit une convention. La convention python pour marquer une classe/fonction/méthode comme privée consiste à la faire précéder d'un _ (trait de soulignement). Par exemple, def _myfunc() ou class _MyClass:. Vous pouvez également créer une pseudo-confidentialité en faisant précéder la méthode de deux traits de soulignement (par exemple: __foo). Vous ne pouvez pas accéder directement à la méthode, mais vous pouvez toujours l'appeler via un préfixe spécial en utilisant le nom de classe (par exemple: _classname__foo). Donc, le mieux que vous puissiez faire est d'indiquer/suggérer la confidentialité, et non de la faire respecter.

Python est comme Perl à cet égard. Pour paraphraser une célèbre ligne sur la vie privée du livre Perl, la philosophie est que vous devez rester hors du salon parce que vous n'étiez pas invité, pas parce qu'il est défendu avec un fusil de chasse.

Pour plus d'informations:

59
Karl Fast

Définissez __all__, une liste de noms que vous souhaitez exporter ( voir documentation ).

__all__ = ['public_class'] # don't add here the 'implementation_class'
35
UncleZeiv

Un modèle que j'utilise parfois est le suivant:

Définissez une classe:

class x(object):
    def doThis(self):
        ...
    def doThat(self):
        ...

Créez une instance de la classe, en écrasant le nom de la classe:

x = x()

Définissez les symboles qui exposent la fonctionnalité:

doThis = x.doThis
doThat = x.doThat

Supprimez l'instance elle-même:

del x

Vous avez maintenant un module qui expose uniquement vos fonctions publiques.

10
theller

La convention ajoute le préfixe "_" aux classes, fonctions et variables internes.

8
Benjamin Peterson

Pour résoudre le problème des conventions de conception, et comme Christopher l'a dit, il n'y a vraiment rien de tel que "privé" en Python. Cela peut sembler tordu pour quelqu'un venant de l'arrière-plan C/C++ (comme moi il y a quelque temps), mais finalement, vous vous rendrez probablement compte que les conventions suivantes suffisent amplement.

Voir quelque chose ayant un trait de soulignement devant devrait être un bon indice pour ne pas l'utiliser directement. Si vous êtes préoccupé par l'encombrement de la sortie help(MyClass) (c'est ce que tout le monde regarde lors de la recherche sur la façon d'utiliser une classe), les attributs/classes soulignés n'y sont pas inclus, donc vous finirez par avoir votre interface "publique" décrite.

De plus, avoir tout public a ses propres avantages géniaux, comme par exemple, vous pouvez tester à peu près n'importe quoi de l'extérieur (ce que vous ne pouvez pas vraiment faire avec des constructions privées C/C++).

4
Dimitri Tcaciuc

Utilisez deux traits de soulignement pour préfixer les noms des identificateurs "privés". Pour les classes d'un module, utilisez un seul soulignement de tête et elles ne seront pas importées à l'aide de "from module import *".

class _MyInternalClass:
    def __my_private_method:
        pass

(Il n'existe pas de véritable "privé" en Python. Par exemple, Python modifie simplement automatiquement les noms des membres de la classe avec des doubles traits de soulignement pour être __clssname_mymember. Donc vraiment, si vous connaissez le nom mutilé, vous pouvez quand même utiliser l'entité "privée". Voir ici. Et bien sûr, vous pouvez choisir d'importer manuellement les classes "internes" si vous le souhaitez).

2
chroder