Quel est le problème avec cela? D'un point de vue objectif et fonctionnel?
import sys
class EncapsulationClass(object):
def __init__(self):
self.privates = ["__dict__", "privates", "protected", "a"]
self.protected = ["b"]
print self.privates
self.a = 1
self.b = 2
self.c = 3
pass
def __getattribute__(self, name):
if sys._getframe(1).f_code.co_argcount == 0:
if name in self.privates:
raise Exception("Access to private attribute \"%s\" is not allowed" % name)
else:
return object.__getattribute__(self, name)
else:
return object.__getattribute__(self, name)
def __setattr__(self, name, value):
if sys._getframe(1).f_code.co_argcount == 0:
if name in self.privates:
raise Exception("Setting private attribute \"%s\" is not allowed" % name)
Elif name in self.protected:
raise Exception("Setting protected attribute \"%s\" is not allowed" % name)
else:
return object.__setattr__(self, name, value)
else:
return object.__setattr__(self, name, value)
example = EncapsulationClass()
example.a = 10 # Exception: Setting private attribute "a" is not allowed
example.b = 10 # Exception: Setting protected attribute "b" is not allowed
example.c = 10 # example.c == 10
example.__dict__["privates"] # Exception: Setting protected attribute "b" is not allowed
Quel serait le problème avec ce genre de chose?
Existe-t-il un meilleur moyen d’encapsuler en Python?
Python a une encapsulation - vous l'utilisez dans votre classe.
Ce qu'il n'a pas, c'est un contrôle d'accès tel que des attributs privés et protégés. Cependant, en Python, il existe une convention de dénomination d'attribut pour désigner les attributs privés en préfixant l'attribut avec un ou deux traits de soulignement, par exemple:
self._a
self.__a
Un simple trait de soulignement indique à l'utilisateur d'une classe qu'un attribut doit être considéré comme privé à la classe et qu'il ne doit pas y avoir accès directement.
Un double trait de soulignement indique la même chose, cependant, Python modifiera quelque peu le nom de l'attribut pour tenter de le masquer.
class C(object):
def __init__(self):
self.a = 123 # OK to access directly
self._a = 123 # should be considered private
self.__a = 123 # considered private, name mangled
>>> c = C()
>>> c.a
123
>>> c._a
123
>>> c.__a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__a'
>>> c._C__a
123
Vous pouvez voir dans le dernier exemple que le nom est passé de __a
à _C__a
, même s'il est toujours accessible dans la classe en tant que self.__a
.
Eh bien, Python n’a pas l’encapsulation comme une sorte de décision "philosophique", de la même manière que nous utilisons beaucoup le dactylo. Personnellement, je ne vois pas l'intérêt d'utiliser des arguments privés ou protégés dans un code Python.
En parlant de votre code, il semble bien fonctionner avec les getters et les setters suivants:
def set_a(self, v):
self.a = v
def get_a(self):
return self.a
si vous apportez la modification suivante à votre dernière ligne de __ getattribute __ (self, name):
return object.__getattribute__(self, name)
Cependant, vous pouvez utilisez une sorte de notion de protection de variable, si vous préfixez vos variables privées avec __, comme le mentionne mhawke. De plus, le commentaire de Daniel souligne une limitation des arguments de votre liste. Vous pouvez conserver le comportement "get/set" protégé en ajoutant "private" et "protected" dans votre liste privée.