Python Property : comment appeler implicitement les méthodes getter et setter ?

Vous pouvez facilement attribuer des valeurs aux attributs d’une classe Python en utilisant Python Property. Les méthodes getter ou setter sont appelées automatiquement lorsque vous utilisez Python Property.

Python Property : de quoi s’agit-il exactement et à quoi sert cette solution ?

La solution Python Property relève d’une technique que les développeurs peuvent utiliser dans le cadre de la programmation orientée objet avec Python. Les programmeurs peuvent ainsi définir des méthodes dont ils peuvent ensuite disposer comme s’il s’agissait d’attributs. Cela leur permet d’accéder de manière plus intuitive aux attributs d’une classe. L’appel des méthodes dédiées setter et getter devient ainsi superflu. La solution Python Property permet de transformer les attributs de classe en propriétés appelées « Managed Attributes ».

Une Python Property permet également de mettre en œuvre une forme de contrôle d’accès : l’utilisation de propriétés permet en effet de s’assurer qu’aucune autre méthode n’accède aux données de l’attribut pour y effectuer des modifications non désirées.

Conseil

Si vous utilisez Python pour réaliser un projet Web, nous vous conseillons également de vous intéresser à la solution Deploy Now. Cet outil pratique vous permet de créer et de déployer votre code en passant directement par GitHub, vous offrant ainsi un énorme avantage en matière d’efficacité pour votre flux de travail.

La fonction Python property()

Les développeurs peuvent avoir recours à la fonction Python property() pour utiliser les propriétés. Ils peuvent tirer parti de cette fonction intégrée sans avoir à importer aucun module supplémentaire. La fonction Python property() est implémentée dans le langage de programmation C, pour des performances optimales.

La syntaxe de la fonction Python property() se présente de la manière suivante :

property(fget=None, fset=None, fdel=None, doc=None)
Python

Les paramètres de la fonction Python property() sont facultatifs. Dans le tableau récapitulatif ci-dessous, vous trouverez la signification de chaque paramètre :

Paramétre Signification
fget Fonction permettant de renvoyer la valeur de l’attribut (méthode getter)
fset Fonction permettant de définir la valeur de l’attribut (méthode setter)
fdel Fonction indiquant la manière dont l’attribut doit être supprimé
doc Chaîne Python décrivant la propriété

Le décorateur Python Property

Il n’est pas nécessaire d’utiliser la fonction property() pour travailler avec des propriétés. Un Python Decorator prédéfini peut souvent être utilisé ; celui-ci vous permet d’utiliser une méthode de votre classe en tant que propriété. Le langage de programmation prend en charge trois décorateurs différents avec leur notation bien connue (en « @ ») vous permettant de définir une propriété :

  • « @property » : identifie une méthode de votre classe en tant que Python Property ;
  • « @property-nom.setter » : spécifie une méthode setter, qui définit la valeur d’une propriété ;
  • « @property-nom.deleter » : spécifie la méthode de suppression d’une propriété.
Note

Si les tutoriels Python plus avancés vous intéressent, nous vous conseillons également de consulter les articles suivants :

Python Property : exemple

Un exemple de code détaillé peut vous aider à prendre la mesure du fonctionnement et de l’utilité de la solution Python Property. Dans la section de code ci-dessous, nous commençons par créer une classe nommée « Chien », avec l’attribut « _nom ». Si cet exemple est particulièrement artificiel et ne présente aucune utilité réelle, il est néanmoins parfait pour illustrer le fonctionnement de la solution Python Property.

class Chien:
	def __init__(self):
		self._nom = "Bello"
Python

Comme vous pouvez le voir, le constructeur ne reçoit aucun paramètre spécifiant le nom de notre chien. Le nom du chien est plutôt spécifié par défaut, à l’aide de la valeur « Bello ». Il est donc possible de créer un objet de la classe avec, par exemple, la ligne de code suivante :

chien = Chien()
Python

Méthodes getter et setter

Vous pouvez améliorer votre classe à l’aide de méthodes getter et setter spécifiques. Cela peut s’avérer judicieux pour plusieurs raisons, notamment parce qu’elles rendent le code plus facile à entretenir et parce qu’elles permettent l’intégration de fonctionnalités supplémentaires. Étant donné que les noms constituent, par défaut, des chaînes de caractères, nous tenons également à nous assurer qu’un nom sous la forme d’une chaîne de caractères est bien transmis dans notre classe. Pour ce faire, nous saisissons la logique fonctionnelle correspondante dans une méthode setter dédiée pour améliorer la précédente définition de notre classe :

class Chien:
	def __init__(self):
		self._nom = "Bello"
	
	def getNom(self):
		return self._nom
	def setNom(self, nom):
		if isinstance(nom, str):
			self._nom = nom
		else:
			return
Python

La méthode setter portant le nom « setNom » est chargée de vérifier, dans une déclaration if…else en Python, si le paramètre transmis correspond bien à une chaîne de caractères. Cela permet, le cas échéant, de définir le nom ; sinon, il ne se passe rien.

Nous avons également choisi de spécifier une méthode getter renvoyant le nom du chien.

Un objet de notre classe appelé « Lassie » peut être créé en suivant l’exemple ci-dessous :

lassie = Chien()
lassie.setNom("Lassie")
print(lassie.getNom())
Python

Le résultat est le suivant (et correspond à ce que nous souhaitions) :

'Lassie'
Note

Contrairement à d’autres langages de programmation, Python n’offre aucune possibilité d’établir une distinction entre les attributs de classe pouvant être utilisés directement depuis l’extérieur, sans aucune méthode getter ni setter (dans d’autres langages de programmation, ces attributs sont souvent caractérisés comme étant « public »), et les attributs de classe ne devant pas être facilement modifiables depuis l’extérieur (dans d’autres langages de programmation, ces attributs sont plutôt caractérisés comme étant « private »). Les conventions veulent donc que les attributs des noms de variable ne devant pas être utilisés sans les méthodes getter et setter commencent par un tiret bas.

Fonction Python property()

Pour éviter d’avoir à recourir à un appel de fonction explicite pour modifier ou connaître le nom de votre chien en Python, vous pouvez maintenant utiliser une Python Property. À des fins de démonstration, nous avons également choisi d’intégrer une déclaration print à chacune de nos méthodes getter et setter.

class Chien:
	def __init__(self):
		self._nom = "Bello"
	def getNom(self):
		print("Appel de la méthode getter")
		return self._nom
	def setNom(self, nom):
		if isinstance(nom, str):
			self._nom = nom
			print("Appel de la méthode setter")
		else:
			return
	
	nom = property(getNom, setNom)
Python

Comme vous pouvez le voir, il nous a suffi de créer un nouvel attribut appelé « nom » (sans placer de tiret bas au début, car la Python Property nous a permis de l’adresser depuis l’extérieur sans aucun problème) et de lui attribuer le résultat de notre appel de fonction pour appeler la fonction property(). Elle a alors reçu les deux méthodes getter et setter que vous connaissez déjà en tant que paramètres.

En créant maintenant un autre objet de la classe nommé « Snoopy », la différence est déjà visible :

snoopy = Chien()
snoopy.nom = "Snoopy"
snoopy.nom
Python

Il est désormais possible d’accéder facilement aux attributs de cette classe en utilisant la notation par points qui doit déjà vous être familière. Ici, le résultat renvoyé par le programme est particulièrement intéressant :

Appel de la méthode setter
Appel de la méthode getter
'Snoopy'

Les méthodes getter et setter n’ont pas été appelées de manière explicite, mais elles ont tout de même été exécutées au moment de l’attribution ou de l’extraction de l’objet « Snoopy » à l’aide de la notation par points. La Python Property nous a permis de parvenir à ce résultat.

Décorateur Python Property

Il est possible d’obtenir le même résultat avec les décorateurs de fonction, dont nous avons déjà parlé. Le cas échéant, l’exemple de code se présente de la manière suivante (les deux méthodes « décorées » doivent avoir le même nom) :

class Chien:
	def __init__(self):
		self._nom = "Bello"
	@property
	def nom(self):
		print("Appel de la méthode setter")
		return self._nom
	@nom.setter
	def nom(self, nom):
		if isinstance(nom, str):
			self._nom = nom
			print("Appel de la méthode getter")
		else:
			return
Python

Il est possible de créer un nouvel objet pour cette classe et d’utiliser la notation par points pour définir et extraire l’attribut « nom » :

struppi = Chien()
struppi.nom = "Struppi"
struppi.nom
Python

Le résultat est le même que celui obtenu en utilisant la fonction Python-property() :

Appel de la méthode setter
Appel de la méthode getter
'Struppi'