Python a-t-il des variables" privées " dans les classes?
je viens du monde Java et je lis Python 3 Patterns, Recipes and Idioms de Bruce Eckels .
en lisant sur les classes, il poursuit en disant qu'en Python il n'y a pas besoin de déclarer les variables d'instance. Vous les utilisez juste dans le constructeur, et boom, ils sont là.
ainsi par exemple:
class Simple:
def __init__(self, s):
print("inside the simple constructor")
self.s = s
def show(self):
print(self.s)
def showMsg(self, msg):
print(msg + ':', self.show())
si c'est vrai, alors n'importe quel objet de la classe Simple
peut changer la valeur de la variable s
en dehors de la classe.
par exemple:
if __name__ == "__main__":
x = Simple("constructor argument")
x.s = "test15" # this changes the value
x.show()
x.showMsg("A message")
en Java, nous avons appris à connaître les variables publiques/privées/protégées. Ces mots-clés, parce que parfois vous voulez des variables dans une classe à laquelle personne n'en dehors de la classe a accès.
Pourquoi n'est-ce pas nécessaire en Python?
11 réponses
c'est culturel. En Python, vous n'écrivez pas aux variables d'instance ou de classe des autres classes. En Java, rien ne vous empêche de faire la même chose si vous vraiment voulez - après tout, vous pouvez toujours éditer la source de la classe elle-même pour obtenir le même effet. Python laisse tomber cette prétention de sécurité et encourage les programmeurs à être responsables. Dans la pratique, cela fonctionne très bien.
si vous voulez émuler des variables privées pour certains raison, vous pouvez toujours utiliser le préfixe __
de PEP 8 . Python mangles les noms de variables comme __foo
, de sorte qu'ils ne sont pas facilement visibles par le code de l'extérieur de la classe qui les contient (bien que vous peut la contourner si vous êtes assez déterminé, tout comme vous peut obtenir autour de Java protections si vous travaillez à lui).
par la même convention, le préfixe _
signifie restez à l'écart même si vous n'êtes pas techniquement empêché de le faire . Vous ne jouez pas avec les variables d'une autre classe qui ressemblent à __foo
ou _bar
.
variables privées en python est plus ou moins un hack: l'interpréteur renomme intentionnellement la variable.
class A:
def __init__(self):
self.__var = 123
def printVar(self):
print self.__var
maintenant, si vous essayez d'accéder à __var
en dehors de la définition de la classe, il échouera:
>>>x = A()
>>>x.__var # this will return error: "A has no attribute __var"
>>>x.printVar() # this gives back 123
mais vous pouvez facilement vous en tirer avec ceci:
>>>x.__dict__ # this will show everything that is contained in object x
# which in this case is something like {'_A__var' : 123}
>>>x._A__var = 456 # you now know the masked name of private variables
>>>x.printVar() # this gives back 456
vous savez probablement que les méthodes dans OOP sont invoquées comme ceci: x.printVar() => A.printVar(x)
, si A.printVar()
peut accéder à un certain champ dans x
, ce champ peut également être accédé à l'extérieur de A.printVar()
...après tout, les fonctions sont créées pour la réutilisabilité, il n'y a aucun pouvoir spécial donné aux déclarations à l'intérieur.
le jeu est différent lorsqu'il y a un compilateur impliqué ( la vie privée est un concept de niveau de compilateur ). Il est au courant de la définition de la classe avec les modificateurs de contrôle d'accès de sorte qu'il peut faire des erreurs si les règles ne sont pas suivies au moment de la compilation
comme l'ont correctement mentionné de nombreux commentaires ci-dessus, n'oublions pas l'objectif principal des modificateurs D'accès: aider les utilisateurs de code à comprendre ce qui est censé changer et ce qui ne l'est pas. Quand vous voyez un champ privé vous ne plaisante pas avec ça. Donc c'est surtout du sucre syntaxique qui est facilement atteint en Python par le _ et __.
"En java, nous avons appris à propos de public/privé/protégé variables"
, "Pourquoi n'est-ce pas nécessaire en python?"
pour la même raison que ce n'est pas requis en Java.
Vous êtes libre de les utiliser-ou n'utilisez pas private
et protected
.
en tant que programmeur Python et Java, j'ai trouvé que private
et protected
sont des concepts de conception très, très importants. Mais d'un point de vue pratique, dans des dizaines de milliers de lignes de Java et Python, je n'ai jamais réellement utilisé private
ou protected
.
pourquoi pas?
voici ma question " protégé de qui?"
d'autres programmeurs dans mon équipe? Ils ont de la source. Que signifie "protégé" quand ils peuvent le changer?
autres programmeurs sur d'autres équipes? Ils travaillent pour la même société. Ils peuvent -- avec un appel téléphonique -- obtenir le code source.
Clients? Il s'agit de programmes de travail pour compte d'autrui (en général). Les clients (généralement) possèdent le code.
donc, de qui -- précisément -- est-ce que je la protège?
exact. Le sociopathe schizophrène qui a refusé de lire les blocs de commentaires de L'API.
il y a une variation des variables privées dans la Convention underscore.
In [5]: class Test(object):
...: def __private_method(self):
...: return "Boo"
...: def public_method(self):
...: return self.__private_method()
...:
In [6]: x = Test()
In [7]: x.public_method()
Out[7]: 'Boo'
In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()
AttributeError: 'Test' object has no attribute '__private_method'
il y a quelques différences subtiles, mais pour le bien de la pureté idéologique de modèle de programmation, son assez bon.
Il ya des exemples là-bas de @décorateurs privés qui mettent en œuvre plus étroitement le concept, mais YMMV. On pourrait sans doute aussi écrire une définition de classe qui utilise meta
Python a un support limité pour les identificateurs privés, grâce à une fonctionnalité qui prépose automatiquement le nom de la classe à tous les identificateurs commençant par deux underscores. C'est transparent pour le programmeur, pour la plupart, mais l'effet net est que les variables nommé de cette façon peuvent être utilisées comme des variables privées.
Voir ici pour en savoir plus.
en général, L'implémentation Python de l'orientation objet est une un peu primitif comparé à d'autres langues. Mais j'aime cela, en fait. Il s'agit d'une mise en œuvre très simple sur le plan conceptuel et qui s'harmonise bien avec le style dynamique du langage.
la seule fois où j'utilise des variables privées est lorsque j'ai besoin de faire d'autres choses en écrivant ou en lisant à partir de la variable et en tant que tel, je dois forcer l'utilisation d'un setter et/ou getter.
encore une fois cela va à la culture, comme déjà indiqué. J'ai travaillé sur des projets où la lecture et l'écriture d'autres variables de classe était gratuite pour tous. Lorsqu'une implémentation est devenue obsolète, il a fallu beaucoup plus de temps pour identifier tous les chemins de code qui utilisaient cette fonction. Lors de l'utilisation de setters et getters ont été forcés, une déclaration de débogage peut facilement être écrite pour identifier que la méthode dépréciée a été appelée et le chemin de code qui l'appelle.
lorsque vous êtes sur un projet où n'importe qui peut écrire une extension, informer les utilisateurs sur les méthodes dépréciées qui doivent disparaître dans quelques versions est donc essentiel pour garder la casse du module à un minimum lors des mises à niveau.
donc ma réponse est; si vous et vos collègues maintenez un jeu de code simple alors protéger les variables de classe n'est pas toujours nécessaire. Si vous écrivez un système extensible alors il devient impératif lorsque des changements au noyau est fait qui doit être attrapé par toutes les extensions en utilisant le code.
les concepts privés et protégés sont très importants. Mais python-juste un outil pour le prototypage et le développement rapide avec des ressources limitées disponibles pour le développement, c'est pourquoi certains niveaux de protection ne sont pas si stricte suivi en python. Vous pouvez utiliser "_ _ " dans membre de la classe, cela fonctionne correctement, mais ne semble pas assez bon - chaque accès à un tel champ contient ces caractères.
aussi, vous pouvez remarquer que le concept python OOP n'est pas parfait, smaltalk ou ruby beaucoup plus proche du pur concept OOP. Même C# ou Java sont plus proches.
Python est un très bon outil. Mais c'est un langage OOP simplifié. Syntaxiquement et conceptuellement simplifié. Le but principal de l'existence de python est d'apporter aux développeurs la possibilité d'écrire du code facilement lisible avec un haut niveau d'abstraction d'une manière très rapide.
comme mentionné plus haut, vous pouvez indiquer qu'une variable ou une méthode est privée en la préfixant avec un underscore. Si vous ne pensez pas que ce soit suffisant, vous pouvez toujours utiliser le décorateur property
. Voici un exemple:
class Foo:
def __init__(self, bar):
self._bar = bar
@property
def bar(self):
"""Getter for '_bar'."""
return self._bar
de cette façon, quelqu'un ou quelque chose qui fait référence à bar
fait réellement référence à la valeur de retour de la fonction bar
plutôt que la variable elle-même, et donc il peut être accédé mais pas changé. Cependant, si quelqu'un voulait vraiment, il pourrait simplement utiliser _bar
et attribuer une nouvelle valeur. Il n'y a aucun moyen sûr pour empêcher quelqu'un d'accéder aux variables et aux méthodes que vous souhaitez cacher, comme cela a été dit à plusieurs reprises. Cependant, utiliser property
est le message le plus clair que vous pouvez envoyer qu'une variable ne doit pas être éditée. property
peut également être utilisé pour des chemins d'accès plus complexes getter/setter/deleter, comme expliqué ici: https://docs.python.org/3/library/functions.html#property
Désolé les gars pour "resurrecting" le fil, mais, j'espère que cela aidera quelqu'un:
en Python3 si vous voulez simplement "encapsuler" les attributs de classe, comme en Java, vous pouvez juste faire la même chose comme ceci:
class Simple:
def __init__(self, str):
print("inside the simple constructor")
self.__s = str
def show(self):
print(self.__s)
def showMsg(self, msg):
print(msg + ':', self.show())
instanciate this do:
ss = Simple("lol")
ss.show()
notez que: print(ss.__s)
va lancer une erreur.
en pratique, Python3 brouillera le nom de l'attribut global. En tournant cette comme un attribut "privé", comme dans Java. Le nom de l'attribut est toujours globale, mais sont inaccessibles façon, comme un attribut privé dans d'autres langues.
mais n'ayez pas peur. Il n'a pas d'importance. Il fait le travail aussi. ;)
Python n'a pas de variables privées comme C++ ou Java. Vous pouvez accéder à n'importe quelle variable membre à tout moment si vous le souhaitez. Cependant, vous n'avez pas besoin de variables privées en Python, car en Python il n'est pas mauvais d'exposer les variables de vos membres de classes. Si vous avez besoin d'encapsuler une variable membre, vous pouvez le faire en utilisant "@property" plus tard sans casser le code client existant.
en python le simple soulignement " _ " est utilisé pour indiquer, qu'une méthode ou une variable n'est pas considérée comme faisant partie de l'api publique d'une classe et que cette partie de l'api pourrait changer entre les différentes versions. Vous pouvez utiliser ces méthodes / variables, mais votre code pourrait casser, si vous utilisez une nouvelle version de cette classe.
le double soulignement " _ _ "ne signifie pas une"variable privée". Vous l'utilisez pour définir les variables qui sont "Classe local" et qui ne peuvent pas être facilement overidden par les sous-classes. Il modifie le nom des variables.
par exemple:
class A(object):
def __init__(self):
self.__foobar = None # will be automatically mangled to self._A__foobar
class B(A):
def __init__(self):
self.__foobar = 1 # will be automatically mangled to self._B__foobar
l'auto.__foobar nom est automatiquement mutilé de soi.___Foobar dans la classe A. Dans la classe B, il est mutilé de soi._ B _ _ foobar. Ainsi, chaque sous-classe peut définir sa propre variable __foobar sans supplanter ses variables parentales. Mais rien ne vous empêche d'accéder aux variables en commençant par les doubles underscores. Cependant, le nom-mangling vous empêche d'appeler ces variables /méthodes incidemment.
je recommande fortement de regarder Raymond Hettingers parler de" pythons class development toolkit "de Pycon 2013 (devrait être disponible sur Youtube), ce qui donne un bon exemple pourquoi et comment vous devriez utiliser @property et "__ _ " - les variables d'instance.