En Python, j'ai l'exemple de classe suivant:
class Foo:
self._attr = 0
@property
def attr(self):
return self._attr
@attr.setter
def attr(self, value):
self._attr = value
@attr.deleter
def attr(self):
del self._attr
Comme vous pouvez le voir, j'ai un simple attribut "privé" "_attr" et une propriété pour y accéder. Il y a beaucoup de codes pour déclarer un simple attribut privé et je pense que ce n'est pas respecter la philosophie "KISS" de déclarer tous les attributs comme ça.
Alors, pourquoi ne pas déclarer tous mes attributs comme des attributs publics si je n'ai pas besoin d'un getter/setter/deleter particulier?
Ma réponse sera: Parce que le principe d'encapsulation (OOP) dit le contraire!
Quel est le meilleur moyen ?
Typiquement, Python s'efforce d'adhérer au niform Access Principle . Spécifiquement, l'approche acceptée est:
foo.x = 0
, Pas foo.set_x(0)
@property
, Qui préserve la sémantique d'accès. Autrement dit, foo.x = 0
Appelle maintenant foo.set_x(0)
.Le principal avantage de cette approche est que l'appelant peut le faire:
foo.x += 1
même si le code peut vraiment faire:
foo.set_x(foo.get_x() + 1)
La première déclaration est infiniment plus lisible. Pourtant, avec les propriétés, vous pouvez ajouter (au début ou plus tard) le contrôle d'accès que vous obtenez avec la deuxième approche.
Notez également que les variables d'instance commençant par un seul trait de soulignement sont classiquement privées. C'est-à-dire que le soulignement signale aux autres développeurs que vous considérez la valeur comme privée, et qu'ils ne devraient pas jouer avec elle directement; cependant, rien dans la langue ne les empêche de les déranger directement.
Si vous utilisez un trait de soulignement double (par exemple, __x
), Python fait un peu d'obscurcissement du nom. La variable est toujours accessible de l'extérieur de la classe, via son nom obscurci) Cependant, ce n'est pas vraiment privé. C'est juste un peu ... plus opaque. Et il y a des arguments valables contre l'utilisation du double soulignement; d'une part, cela peut rendre le débogage plus difficile.
Le "dunder" (double soulignement, __
) le préfixe empêche l'accès à l'attribut, sauf par le biais d'accesseurs.
class Foo():
def __init__(self):
self.__attr = 0
@property
def attr(self):
return self.__attr
@attr.setter
def attr(self, value):
self.__attr = value
@attr.deleter
def attr(self):
del self.__attr
Quelques exemples:
>>> f = Foo()
>>> f.__attr # Not directly accessible.
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> '__attr' in f.__dir__() # Not listed by __dir__()
False
>>> f.__getattribute__('__attr') # Not listed by __getattribute__()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__attr'
>>> f.attr # Accessible by implemented getter.
0
>>> f.attr = 'Presto' # Can be set by implemented setter.
>>> f.attr
'Presto'
>>> f.__attr = 'Tricky?' # Can we set it explicitly?
>>> f.attr # No. By doing that we have created a
'Presto' # new but unrelated attribute, same name.
Tout simplement, les principes OOP sont faux. Pourquoi c'est une longue discussion qui mène à des guerres enflammées et est probablement hors sujet pour ce site. :-)
Dans Python il n'y a pas d'attributs privés, vous ne pouvez pas les protéger, et ce n'est jamais un vrai problème. Alors ne le faites pas. Facile! :)
Vient ensuite la question: si vous avez un trait de soulignement ou non. Et dans l'exemple que vous avez ici, vous ne devriez certainement pas. Un trait de soulignement principal dans Python est une convention pour montrer que quelque chose est interne, et ne fait pas partie de l'API, et que vous devez l'utiliser à vos propres risques. Ce n'est évidemment pas le cas ici , mais c'est une convention commune et utile.
Python n'a pas d'attributs publics OR privés. Tous les attributs sont accessibles à tout le code.
self.attr = 0 #Done
Votre méthode ne rend en rien _attr privé, c'est juste un peu d'obscurcissement.
Voir ce lien: https://docs.python.org/2/tutorial/classes.html
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éfixé par 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 tête, au plus un trait de soulignement de fin) est textuellement remplacé par _classname__spam, où classname est le nom de classe actuel avec le ou les traits de soulignement de tête 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.
Comme d'autres l'ont dit, les attributs privés dans Python ne sont qu'une convention. L'utilisation de la syntaxe property
doit être utilisée pour un traitement spécial lorsque les attributs sont liés, modifiés ou supprimés. La beauté of Python est que vous pouvez commencer en utilisant simplement la liaison d'attribut normale, par exemple, self.attr = 0
et si, à une date ultérieure, vous décidez de restreindre la valeur de attr à 0 <= attr <=100
, vous pouvez créer attr
une propriété et définir une méthode pour vous assurer que cette condition est vraie sans jamais avoir à changer de code utilisateur.
Pour rendre un attribut privé, il suffit de faire self.__attr
class Foo:
self.__attr = 0
@property
def attr(self):
return self._attr
@attr.setter
def attr(self, value):
self._attr = value
@attr.deleter
def attr(self):
del self._attr
En Python, à moins que vous n'ayez besoin d'un comportement spécial d'un attribut, il n'est pas nécessaire de le cacher derrière les méthodes d'accesseur. Si un attribut est destiné à un usage interne uniquement, ajoutez-le avec un trait de soulignement.
La bonne chose à propos des propriétés est qu'elles vous ont donné une interface vraiment cool pour travailler avec. Parfois, il est pratique de dériver une propriété en fonction d'une autre (par exemple, l'IMC est défini par le poids et la taille). L'utilisateur de l'interface n'a bien sûr pas besoin de le savoir.
Je préfère cette façon plutôt que d'avoir des getters et setters explicites comme dans Java ie. Beaucoup plus agréable. :)