Question

Je viens du monde Java et je lis Les modèles, les recettes et les idiomes Python 3 de Bruce Eckels .

Tout en lisant sur les classes, il est dit que dans Python il n’est pas nécessaire de déclarer des variables d’instance. Vous les utilisez simplement dans le constructeur et boum, 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 cela est vrai, alors tout objet de la classe Simple peut simplement 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, on nous a enseigné les variables publiques / privées / protégées. Ces mots clés ont du sens car vous souhaitez parfois des variables dans une classe auxquelles personne en dehors de la classe n’a accès.

Pourquoi cela n'est-il pas requis en Python?

Était-ce utile?

La solution

C'est culturel. En Python, vous n'écrivez pas dans l'instance ou les variables de classe d'autres classes. En Java, rien ne vous empêche de faire la même chose si vous voulez vraiment - après tout, vous pouvez toujours éditer la source de la classe elle-même pour obtenir le même effet. Python abandonne ce prétexte de sécurité et encourage les programmeurs à être responsables. En pratique, cela fonctionne très bien.

Si vous souhaitez émuler des variables privées pour une raison quelconque, vous pouvez toujours utiliser le préfixe __ de PEP 8 . Python modifie les noms de variables telles que __ foo afin qu’elles ne soient pas facilement visibles en dehors de la classe qui les contient (bien que vous puissiez le contourner si vous êtes déterminé). comme vous pouvez contourner les protections de Java si vous y travaillez).

Selon la même convention, le préfixe _ signifie que restez à l'écart même si rien ne vous empêche techniquement de le faire . Vous ne jouez pas avec les variables d'une autre classe qui ressemblent à __ foo ou à _bar .

Autres conseils

Les variables privées en python sont plus ou moins un hack: l’interprète 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, cela é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:

 >>>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 de POO sont appelées comme suit: x.printVar () = > A.printVar (x) , si A.printVar () peut accéder à un champ de x , vous pouvez également accéder à ce champ en dehors A.printVar () ... après tout, les fonctions sont créées pour pouvoir être réutilisées. Aucun pouvoir spécial n'est donné aux instructions qu'il contient.

Le jeu est différent lorsqu'un compilateur est impliqué ( la confidentialité est un concept de niveau compilateur ). Il connaît la définition de classe avec les modificateurs de contrôle d’accès afin qu’il puisse renvoyer une erreur si les règles ne sont pas suivies à la compilation

Comme mentionné à juste titre dans bon nombre des commentaires ci-dessus, n'oublions pas l'objectif principal de Access Modifiers: aider les utilisateurs de code à comprendre ce qui est supposé changer et ce qui est supposé ne pas l'être. Lorsque vous voyez un champ privé, vous ne le dérangez pas. Il s’agit donc principalement du sucre syntaxique qui est facilement obtenu en Python par le _ et le __.

"En Java, on nous a enseigné les variables publiques / privées / protégées"

"Pourquoi cela n'est-il pas requis en python?"

Pour la même raison, il n'est pas requis en Java.

Vous êtes libre d'utiliser - ou de ne pas utiliser privé et protégé .

En tant que programmeur Python et Java, j'ai constaté que private et protected sont des concepts de conception très, très importants. Mais dans la pratique, dans des dizaines de milliers de lignes de Java et de Python, je n’ai jamais réellement utilisé privé ou protégé .

Pourquoi pas?

Voici ma question "protégé de qui?"

D'autres programmeurs de mon équipe? Ils ont la source. Que signifie protégé quand ils peuvent le changer?

D'autres programmeurs sur d'autres équipes? Ils travaillent pour la même entreprise. Avec un appel téléphonique, ils peuvent obtenir la source.

Clients? C'est une programmation de travail pour le compte d'employés (en général) Les clients (généralement) possèdent le code.

Alors, précisément - de qui est-ce que je le protège?

Il existe une variation de variables privées dans la convention de soulignement.

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 existe quelques différences subtiles, mais pour des raisons de programmation, la pureté idéologique est suffisante.

Il existe des exemples de décorateurs @private qui appliquent plus étroitement le concept, mais YMMV. On pourrait également écrire une définition de classe qui utilise la méta

Python prend en charge les identifiants privés de manière limitée, grâce à une fonctionnalité qui ajoute automatiquement le nom de la classe à tout identifiant commençant par deux traits de soulignement. Ceci est transparent pour le programmeur, dans la plupart des cas, mais l’effet final est que toutes les variables nommées de cette manière peuvent être utilisées comme variables privées.

Voir ici pour plus d'informations à ce sujet.

En général, la mise en œuvre de l'orientation des objets par Python est un peu primitive par rapport à d'autres langages. Mais j'aime ça, en fait. C’est une implémentation très simple sur le plan conceptuel qui cadre bien avec le style dynamique du langage.

Comme mentionné précédemment, vous pouvez indiquer qu'une variable ou une méthode est privée en la préfixant avec un trait de soulignement. Si vous pensez que cela ne suffit pas, vous pouvez toujours utiliser le décorateur propriété . 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, une personne ou quelque chose qui fait référence à la barre fait en réalité référence à la valeur de retour de la fonction barre plutôt qu'à la variable elle-même. Vous pouvez donc y accéder mais pas modifié. Cependant, si quelqu'un le voulait vraiment, il pourrait simplement utiliser _bar et lui attribuer une nouvelle valeur. Il n'y a pas de moyen sûr d'empêcher quelqu'un d'accéder aux variables et aux méthodes que vous souhaitez masquer, comme cela a été dit à plusieurs reprises. Cependant, utiliser property est le message le plus clair que vous pouvez envoyer pour indiquer qu'une variable ne doit pas être modifiée. La propriété peut également être utilisée pour des chemins d'accès getter / setter / deleter plus complexes, comme expliqué ici: https://docs.python.org/3/library/functions.html#property

La seule fois où j'utilise des variables privées, c'est quand je dois faire d'autres choses pour écrire ou lire dans la variable et, par conséquent, je dois forcer l'utilisation d'un séparateur et / ou d'un getter.

Encore une fois, cela va à la culture, comme déjà dit. J'ai travaillé sur des projets où lire et écrire des variables de classes était gratuit. Lorsqu'une implémentation est devenue obsolète, l'identification de tous les chemins de code utilisant cette fonction a pris beaucoup plus de temps. Lorsque l'utilisation de setters et de getters était forcée, une instruction de débogage pouvait facilement être écrite pour indiquer que la méthode obsolète avait été appelée et le chemin de code qui l'appelle.

Lorsque vous êtes sur un projet où tout le monde peut écrire une extension, informer les utilisateurs des méthodes obsolètes qui doivent disparaître dans quelques éditions est donc essentiel pour limiter au minimum la casse de modules lors des mises à niveau.

Donc ma réponse est; Si vous et vos collègues maintenez un jeu de codes simple, la protection des variables de classe n'est pas toujours nécessaire. Si vous écrivez un système extensible, il devient impératif d’apporter des modifications au noyau qui doivent être interceptées par toutes les extensions utilisant le code.

Les concepts privés et protégés sont très importants. Mais python - juste un outil de prototypage et de développement rapide avec des ressources limitées disponibles pour le développement, c’est pourquoi certains niveaux de protection ne sont pas aussi stricts que ceux suivis en python. Vous pouvez utiliser " __ " Dans la classe, cela fonctionne correctement, mais ne semble pas assez bon - chaque accès à un tel champ contient ces caractères.

En outre, vous pouvez remarquer que le concept de programmation orientée objet en python n’est pas parfait, que le smaltalk ou le rubis se rapprochent beaucoup du concept de programmation orientée objet. Même C # ou Java sont plus proches.

Python est un très bon outil. Mais c'est un langage simplifié OOP. Syntaxiquement et conceptuellement simplifié. L’existence de python a pour objectif principal d’offrir aux développeurs la possibilité d’écrire très rapidement un code lisible facilement avec un niveau d’abstraction élevé.

Désolé, les gars pour "ressusciter". 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 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())

Pour instancier ceci faire:

ss = Simple("lol")
ss.show()

Notez que: print (ss .__s) provoquera une erreur.

En pratique, Python3 masquera le nom de l'attribut global. En tournant ceci comme un "privé" attribut, comme en Java. Le nom de l'attribut est toujours global, mais de manière inaccessible, comme un attribut privé dans d'autres langues.

Mais n’ayez pas peur de ça. Ça n'a pas d'importance. Cela fait aussi le travail. ;)

Python n'a pas de variables privées comme C ++ ou Java. Vous pouvez également 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 membre de votre classe. Si vous avez besoin d'encapsuler une variable membre, vous pouvez le faire en utilisant " @ property " plus tard sans rompre le code client existant.

En python, le trait de soulignement simple "_". est utilisé pour indiquer qu'une méthode ou une variable n'est pas considérée comme faisant partie de l'api public d'une classe et que cette partie de l'api pourrait changer d'une version à l'autre. Vous pouvez utiliser ces méthodes / variables, mais votre code pourrait se rompre si vous utilisez une version plus récente de cette classe.

Le soulignement double " __ " ne signifie pas une "variable privée". Vous l'utilisez pour définir des variables qui sont "class local". et qui ne peuvent pas être facilement oubliés 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

self .__ Le nom de foobar est automatiquement mutilé ._A__foobar en classe A. En classe B, il est mutilé à soi-même._B__foobar. Ainsi, chaque sous-classe peut définir sa propre variable __foobar sans remplacer ses variables parents. Mais rien ne vous empêche d’accéder aux variables commençant par des doubles tirets bas. Cependant, la gestion des noms vous empêche d'appeler incidemment ces variables / méthodes.

Je recommande vivement de regarder Raymond Hettingers parler du "Kit de développement de classes Pythons". Pycon 2013 (devrait être disponible sur Youtube), qui donne un bon exemple de la raison pour laquelle vous devriez utiliser les propriétés @property et "__", ainsi que les variables "__".

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top