Historique de la question :
Dans la POO classique, l'encapsulation est réalisée via des champs privés et des getters/setters, ce qui est encombrant et "pas pythonique". En Python, à partir de la version 2.2, le décorateur @property est apparu, permettant d'accéder aux méthodes-getters et setters comme s'il s'agissait d'attributs ordinaires, réalisant ainsi une encapsulation soignée avec une syntaxe pratique.
Problème :
Sans les décorateurs de propriété, il faut définir explicitement des méthodes pour accéder et attribuer des valeurs (par exemple, get_x() et set_x(val)), ce qui rend le code moins lisible et expose les utilisateurs de la classe à un accès direct aux données internes. Cela entraîne des problèmes lors du refactoring et des changements internes de la logique de stockage ou de calcul des valeurs.
Solution :
Le décorateur @property permet de définir les getters, setters et deleters avec une syntaxe unique. Cela semble concis, pratique, encapsule les détails d'implémentation et permet de changer le moyen de calcul d'une propriété sans violer l'interface de la classe.
Exemple de code :
class Temperature: def __init__(self, celsius): self._celsius = celsius @property def celsius(self): return self._celsius @celsius.setter def celsius(self, value): if value < -273.15: raise ValueError("La température en dessous de -273.15°C n'est pas possible !") self._celsius = value
Caractéristiques clés :
@property permet d'accéder aux méthodes comme à des attributs ordinaires.Peut-on créer une propriété en lecture seule et non en écriture/suppression ?
Oui, si l'on définit uniquement une méthode avec le décorateur @property sans setter ni deleter, la propriété sera en lecture seule.
class Sample: @property def value(self): return 42
Que se passe-t-il si le nom de la property correspond à un attribut privé ?
En général, la propriété est utilisée comme "couche" pour un attribut privé, dont le nom commence par un soulignement (par exemple, _x). Il convient d'éviter de telles collisions, sinon cela entraînera un appel récursif :
class Bad: @property def x(self): return self.x # Récursion infinie
Peut-on affecter une propriété uniquement à la classe ?
Non, le standard @property fonctionne avec des instances de classe. Pour créer une propriété de classe, il faut utiliser des motifs externes ou des bibliothèques spécifiques (@classmethod avec property ne fonctionne pas directement).
Un développeur accède directement au champ de la classe (self.celsius), plutôt que via la property. Par la suite, une validation est ajoutée, mais les consommateurs de la classe peuvent toujours modifier directement l'attribut privé et contourner les vérifications.
Avantages :
Il est simple et rapide de travailler tant qu'il n'y a pas de logique complexe.
Inconvénients :
L'encapsulation est violée, il est facile d'obtenir un état invalide de l'objet, cela peut créer de la confusion.
Utilisation de la property et de la dissimulation de l'attribut interne via _celsius. La validation, la mise en cache et la logique sont centralisées à l'intérieur de la property.
Avantages :
Le code est protégé, l'interface est stable — on peut changer l'implémentation de la propriété sans impact sur les utilisateurs de la classe.
Inconvénients :
Avec de grands objets complexes, la complexité de débogage peut augmenter si l'on abuse des properties.