web-dev-qa-db-fra.com

Membres privés dans Python

Comment puis-je rendre les méthodes et les membres de données privés en Python? Ou Python ne prend-il pas en charge les membres privés?

61
appusajeev

9.6. Variables privées

Les variables d'instance "privées" auxquelles on ne peut accéder que depuis l'intérieur d'un objet, n'existent pas en Python. Cependant, il existe une convention qui est suivie par la plupart des Python: un nom précédé d'un trait de soulignement (par exemple _spam) doit être traité comme une partie non publique de l'API (que ce soit un fonction, une méthode ou un membre de données. Il doit être considéré comme un détail d'implémentation et sujet à changement sans préavis.

Puisqu'il existe un cas d'utilisation valide pour les membres privés de classe (à savoir pour éviter les conflits de noms avec des noms définis par des sous-classes), il existe un support limité pour un tel mécanisme, appelé gestion de noms. Tout identifiant de la forme __spam (au moins deux traits de soulignement de début, au plus un trait de soulignement de fin) est textuellement remplacé par _classname__spam, où nom_classe est le nom de la classe actuelle avec les traits de soulignement principaux supprimés. Cette manipulation est effectuée sans tenir compte de la position syntaxique de l'identifiant, tant qu'elle se produit dans la définition d'une classe.

Donc, par exemple ,

class Test:
    def __private_symbol(self):
        pass
    def normal_symbol(self):
        pass

print dir(Test)

affichera:

['_Test__private_symbol', 
'__doc__', 
'__module__', 
'normal_symbol']

__private_symbol devrait être considérée comme une méthode privée, mais elle serait toujours accessible via _Test__private_symbol.

75
jbochi

Les autres réponses fournissent les détails techniques. Je voudrais souligner la différence de philosophie entre Python d'une part et des langages comme C++/Java (dont je suppose que vous êtes familier en fonction de votre question).

L'attitude générale dans Python (et Perl d'ailleurs) est que la "confidentialité" d'un attribut est une demande au programmeur plutôt qu'une clôture en fil de fer barbelé par le compilateur/interprète. L'idée est bien résumé dans cet e-mail et est souvent appelé "Nous sommes tous des adultes consentants" car il "suppose" que le programmeur est suffisamment responsable pour ne pas se mêler de l'intérieur. un message poli disant que l'attribut est interne.

D'un autre côté, si vous voulez accéder aux composants internes de certaines applications (un exemple notable est les générateurs de documentation comme pydoc), vous êtes libre de faites-le. Il vous incombe en tant que programmeur de savoir ce que vous faites et de le faire correctement plutôt que sur le langage pour vous forcer à faire les choses c'est comme ça.

34
Noufal Ibrahim

Il n'y a pas de private d'aucun autre mécanisme de protection d'accès en Python. Il existe une convention documentée dans le guide de style Python pour indiquer aux utilisateurs de votre classe qu'ils ne doivent pas accéder à certains attributs.

  • _single_leading_underscore: faible indicateur "usage interne". Par exemple. from M import * N'importe pas les objets dont le nom commence par un trait de soulignement.

  • single_trailing_underscore_: utilisé par convention pour éviter les conflits avec le mot clé Python, par exemple Tkinter.Toplevel(master, class_='ClassName')

  • __double_leading_underscore: lorsque vous nommez un attribut de classe, invoque la modification de nom (à l'intérieur de la classe FooBar, __boo devient _FooBar__boo; voir ci-dessous).

6
Tendayi Mawushe

Si le nom d'une fonction Python, méthode de classe ou attribut commence par (mais ne se termine pas par) deux traits de soulignement, il est privé; tout le reste est public. Python n'a pas de concept de méthodes de classe protégées (accessible uniquement dans leur propre classe et classes descendantes). Les méthodes de classe sont soit privées (accessibles uniquement dans leur propre classe) ou public (accessible de partout).

Plongez dans Python

6
Svetlozar Angelov

Python ne prend pas directement en charge la confidentialité. Le programmeur doit savoir quand il est sûr de modifier l'attribut de l'extérieur mais de toute façon avec python vous pouvez réaliser quelque chose comme privé avec de petites astuces. Maintenant voyons une personne peut mettre quelque chose de privé ou non.

 classe Personne (objet): 
 
 def __priva (self): 
 print "I am Private" 
 
 def publ (auto): 
 imprimer "Je suis public" 
 
 def callpriva (self): 
 self .__ priva () 

Maintenant, quand nous exécuterons:

 >>> p = Personne () 
 >>> p.publ () 
 Je suis public 
 >>> p .__ priva () 
 Traceback (dernier appel le plus récent): 
 Fichier "", ligne 1, dans 
 P .__ priva () 
 AttributeError: l'objet 'Person' n'a pas d'attribut '__priva' 
 #Explication: Vous pouvez voir ici que nous ne pouvons pas récupérer directement cette méthode privée. 
 >>> p.callpriva () 
 Je suis privé 
 # Explication: Ici, nous pouvons accéder à une méthode privée à l'intérieur de la classe 

Alors comment quelqu'un peut accéder à cette variable ???
Vous pouvez faire comme:

 >>> p._Person__priva 
 Je suis un soldat 

Wow, en fait si python obtient que toute variable commençant par un double soulignement soit "traduite" en ajoutant un seul soulignement et le nom de la classe au début:

Note: Si vous ne voulez pas que ce nom change mais que vous voulez quand même envoyer un signal pour que les autres objets restent à distance, vous pouvez utiliser un seul soulignement initial les noms avec un soulignement initial ne sont pas importés avec les étoiles importations (à partir de l'importation de modules *)
Exemple :

 # test.py 
 def hello (): 
 print "hello" 
 def _hello (): 
 print "Hello private" 
 
 # ---------------------- 
 # test2.py 
 à partir de l'importation de test * 
 print hello () 
 print _hello () 

sortie ->

 bonjour 
 Traceback (dernier appel le plus récent): 
 Fichier "", ligne 1, dans 
 NameError: le nom '_hello' n'est pas défini 

Maintenant, si nous appelons _hello manuellement.

 # test2.py 
 de test import _hello, hello 
 print hello () 
 print _hello () 

sortie ->

 bonjour 
 bonjour privé 

Enfin: Python n'a pas vraiment de support de confidentialité équivalent, bien que les soulignements initiaux simples et doubles vous offrent dans une certaine mesure deux niveaux de confidentialité

5
Prashant Gaur

Cela pourrait fonctionner:

import sys, functools

def private(member):
    @functools.wraps(member)
    def wrapper(*function_args):
      myself = member.__name__
      caller = sys._getframe(1).f_code.co_name
      if (not caller in dir(function_args[0]) and not caller is myself):
         raise Exception("%s called by %s is private"%(myself,caller))
      return member(*function_args)
    return wrapper

class test:
   def public_method(self):
      print('public method called')

   @private
   def private_method(self):
      print('private method called')

t = test()
t.public_method()
t.private_method()
2
Laszlo

C'est un peu une réponse l-o-n-g mais je pense que cela va à la racine du vrai problème ici - l'étendue de la visibilité. Accrochez-vous là-bas pendant que je fouille à travers ça!

La simple importation d'un module ne donne pas nécessairement au développeur de l'application un accès à toutes ses classes ou méthodes; si je ne peux pas réellement VOIR le code source du module, comment saurai-je ce qui est disponible? Quelqu'un (ou quelque chose) doit me dire ce que je peux faire et expliquer comment utiliser les fonctionnalités que je suis autorisé à utiliser, sinon tout cela ne me sert à rien.

Ceux qui développent des abstractions de niveau supérieur basées sur des classes et des méthodes fondamentales via des modules importés sont présentés avec un DOCUMENT de spécification - PAS le code source réel.

La spécification du module décrit toutes les fonctionnalités destinées à être visibles par le développeur client. Lorsqu'il s'agit de grands projets et d'équipes de projets logiciels, la mise en œuvre réelle d'un module doit TOUJOURS rester cachée à ceux qui l'utilisent - c'est une boîte noire avec une interface avec le monde extérieur. Pour les puristes OOD, je crois que les termes techniques sont "découplage" et "cohérence". L'utilisateur du module n'a qu'à connaître les méthodes d'interface sans être gêné par les détails de mise en œuvre.

Un module ne doit JAMAIS être modifié sans avoir au préalable modifié son document de spécification sous-jacent, ce qui peut nécessiter une révision/approbation dans certaines organisations avant de modifier le code.

En tant que programmeur amateur (retraité maintenant), je démarre un nouveau module avec le document de spécification réellement écrit sous la forme d'un bloc de commentaires géant en haut du module, ce sera la partie que l'utilisateur voit réellement dans la bibliothèque de spécifications. Puisque c'est juste moi, je n'ai pas encore mis en place une bibliothèque, mais ce serait assez facile à faire.

Ensuite, je commence à coder en écrivant les différentes classes et méthodes mais sans corps fonctionnels - juste des instructions d'impression nulles comme "print ()" - juste assez pour permettre au module de compiler sans erreurs de syntaxe. Lorsque cette étape est terminée, je compile le module nul terminé - c'est ma spécification. Si je travaillais sur une équipe de projet, je présenterais cette spécification/interface pour examen et commentaires avant de procéder à l'étoffage du corps.

J'étoffe les corps de chaque méthode une par une et compile en conséquence, en veillant à ce que les erreurs de syntaxe soient corrigées immédiatement à la volée. C'est aussi le bon moment pour commencer à écrire une section d'exécution "principale" temporaire en bas pour tester chaque méthode pendant que vous la codez. Une fois le codage/test terminé, tout le code de test est mis en commentaire jusqu'à ce que vous en ayez à nouveau besoin si des mises à jour s'avèrent nécessaires.

Dans une équipe de développement du monde réel, le bloc de commentaires spec apparaîtrait également dans une bibliothèque de contrôle de document, mais c'est une autre histoire. Le fait est que vous, en tant que client du module, voyez uniquement cette spécification et NON le code source.

PS: bien avant le début des temps, je travaillais dans la communauté aérospatiale de la défense et nous avons fait des trucs plutôt sympas, mais des choses comme les algorithmes propriétaires et la logique de contrôle des systèmes sensibles étaient étroitement voûtées et cryptées dans des bibliothèques de logiciels sécurisées ultra-duper. Nous avions accès aux interfaces module/package mais PAS aux corps d'implémentation blackbox. Il y avait un outil de gestion des documents qui gérait toutes les conceptions au niveau du système, les spécifications logicielles, le code source et les enregistrements de test - tout était synchronisé ensemble. Le gouvernement avait des normes strictes d'assurance qualité des logiciels. Quelqu'un se souvient d'une langue appelée "Ada"? Voilà mon âge!

2
We_Are_Borg

J'utilise Python 2.7 et 3.5. J'ai écrit ce code:

class MyOBject(object):
    def __init__(self):
        self.__private_field = 10


my_object = MyOBject()
print(my_object.__private_field)

l'a exécuté et a obtenu:

AttributeError: l'objet 'MyOBject' n'a pas d'attribut '__private_field'

Veuillez voir: https://www.tutorialsteacher.com/python/private-and-protected-access-modifiers-in-python

0
CrazySynthax