Portée des attributs d'objets¶
La portée de la variable a été introduite à la leçon 2 Portée des variables. Les objets et les classes étant des variables (oui, une classe aussi), leur portée suit les même règles, mais qu'en est-il de la portée des attributs des objets et des classes ?
- Par défaut les attributs sont accessibles (visibles) là où l'objet est visible.
- Les attributs d'un objet meurent quand leur objet meurt.
Cependant, il est possible de restreindre la portée d'un attribut en le rendant privée afin qu'il ne soit accessible qu'à l'intérieur de l'objet. Ce n'est pas techniquement vrai en Python mais cela fonctionne de la même manière en respectant des conventions.
Variables privées¶
Les variables privées dans une classe sont des variables destinées à être utilisées uniquement dans la classe. En étant privé, elles sont protégées de toute modification extérieure.
Contrairement à C ++, Python n'a pas de méthodes privées ni de variables privées. Mais une convention consiste à nommer une variable spécialement pour indiquer si elle est faiblement ou fortement privée:
_x
Une variable qui commence par un trait de soulignement et ne finit pas par un trait de soulignement signifie qu'elle est peu privée, c'est-à-dire que Python ne fera rien pour le protéger, mais les programmeurs sont avertis qu'ils ne doivent pas l'utiliser en dehors de la classe.__x
Une variable qui commence par 2 caractères de soulignement et ne finit pas par 2 caractères de soulignement signifie que les données sont fortement privée, c'est-à-dire que Python la protégera des modifications en la renommant. Cependant, elle peut toujours être modifiée en utilisant son nouveau nom.
Ainsi,
- lorsque vous voulez une variable privée pouvant être utilisée par les classes enfant, utilisez faiblement privé
_
. - lorsque vous souhaitez utiliser une variable privée uniquement dans sa classe et non dans les classes enfants, utilisez fortement privé
__
.
class A(object):
def __init__(self):
self._x = 0
self.__y = 1
class B(A):
def __init__(self):
super().__init__()
def print(self):
print(self._x)
print(self.__y) # does not work
b = B()
print(b._x) # it works but it is bad to call a private variable outside its class
b.print()
0 0
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-1-273d0701a1f7> in <module> 14 b = B() 15 print(b._x) # it works but it is bad to call a private variable outside its class ---> 16 b.print() <ipython-input-1-273d0701a1f7> in print(self) 10 def print(self): 11 print(self._x) ---> 12 print(self.__y) # does not work 13 14 b = B() AttributeError: 'B' object has no attribute '_B__y'
Méthodes privées¶
Même chose avec les méthodes.
class A(object):
def _f(self):
print('A.f')
def __g(self):
print('A.g')
class B(A):
def f(self):
self._f()
def g(self):
self.__g()
b = B()
b.f()
b.g()
A.f
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-2-17cb3613e146> in <module> 15 b = B() 16 b.f() ---> 17 b.g() <ipython-input-2-17cb3613e146> in g(self) 11 12 def g(self): ---> 13 self.__g() 14 15 b = B() AttributeError: 'B' object has no attribute '_B__g'
On notera que le message d'erreur donne la clef pour accéder à un attribut fortement privée (même si cela n'a pas d'intérêt) : _<nom classe><attribut>
donc
class B(A):
def f(self):
self._f()
def g(self):
self._A__g() # adding class name allows to access to very private attribute (don't do it!)
b = B()
b.f()
b.g()
A.f A.g
La raison pour laquelle c'est possible est la même que la raison pour laquelle il n'y a pas de constante : nous sommes des adultes, si on respecte les conventions tout ira bien.
{{ PreviousNext("02 Inheritance.ipynb", "04 View vs Copy.ipynb")}}