Attributs de méthodes spéciaux en Python

Gazette Linux n°54 — Juin 2000

Martin Quinson

Adaptation française 

Frédéric Marchal

Correction du DocBook 

Article paru dans le n°54 de la Gazette Linux de juin 2000.

Cet article est publié selon les termes de la Open Publication License. La Linux Gazette n'est ni produite, ni sponsorisée, ni avalisée par notre hébergeur principal, SSC, Inc.


Table des matières

Les classes et objets en python
La méthode spéciale __add__
Un autre usage de __add__
Comment les objets s'affichent eux même — la méthode spéciale __str__
Tester la valeur de vérité avec __nonzero__
La magie de __getitem__
Accéder aux attributs avec __getattr__
Pour en savoir plus

Les programmeurs C++ utilisent la « surcharge d'opérateurs » pour appliquer les opérations de base sur les classes définies par l'utilisateur. Par exemple, une classe de nombres complexes peut contenir un opérateur d'addition qui rend possible l'usage d'objets de type « complexe » dans une expression arithmétique, de la même manière que des nombres entiers ou flottants. Le langage Python offre le même genre de fonctionnalité de manière simple et élégante grâce aux attributs de méthode.

Cet article est une rapide introduction à certaines méthodes au travers de morceaux de code que j'ai écris en lisant le guide de références. Le code a été testé avec Python version 1.5.1.

Les classes et objets en python

Voyons une simple définition de classe en Python :

class toto:
	def __init__(self, n):
		print 'le constructeur est appelé'
		self.n = n
		
	def hello(self):
		print 'Bonjour, monde'
		
	def change(self, n):
		print 'Change self.n'
		self.n = n

f = toto(10) # crée une instance de la classe foo avec un champ de données
	     # 'n' ayant la valeur 10.
print f.n    # affiche 10. Python ne gère pas les contrôles d'accès aux
	     # membres comme C++ le fait.
f.m = 20     # Vous pouvez même ajouter de nouveaux champs !
f.hello()    # affiche 'Bonjour, monde'
toto.change(f, 40)
print f.n    # affiche 40

La méthode __init__ est similaire au « constructeur » de C++. C'est une méthode spéciale appelée automatiquement à la création de l'objet.

Remarquons que toutes les fonctions membres ont un argument nommé « self » et représentant l'objet lui même. Ainsi, appeler f.hello() revient à appeler une méthode appartenant à la classe toto avec l'objet f en premier paramètre. Ce paramètre est habituellement nommé « self ». Bien qu'il soit possible de lui donner n'importe quel nom, il est conseillé de suivre cette convention. Les programmeurs C++ trouverons sans doute un rapport entre « self » et le mot clé « this », qui est dans ce langage le premier paramètre (caché) des invocations de méthodes.

La méthode spéciale __add__

Considérons la définition de classe suivante :

class toto:
	def __init__(self, n):
		self.n = n
	def __add__(self, right):
		t = toto(0) 
		t.n = self.n + right.n
		return t

Maintenant, créons deux objets f1 et f2 de type « toto » et additionnons les :

f1 = toto(10)  # f1.n vaut 10
f2 = toto(20)  # f2.n vaut 20
f3 = f1 + f2  
print f3.n    # affiche 30

Que ce passe-t-il quand Python exécute f1+f2 ? En fait, l'interpréteur appelle simplement f1.__add__(f2). Ainsi, « self » désigne f1 dans la fonction __add__, et « right » désigne f2.

Un autre usage de __add__

Voyons une autre façon d'utiliser la fonction spéciale __add__ :

class toto:
	def __init__(self, n):
		self.n = n
	def __radd__(self, left):
		t = toto(0) 
		t.n = self.n + left.n
		print 'left.n vaut', left.n
		return t
	
f1 = toto(10)
f2 = toto(20)
f3 = f1 + f2  # affiche 'left.n vaut 10'

La différence est que dans ce cas, f1+f2 est converti en f2.__add__(f1).

Comment les objets s'affichent eux même — la méthode spéciale __str__

class toto:
	def __init__(self, n1, n2):
		self.n1 = n1
		self.n2 = n2
	
	def __str__(self):
		return 'Instance de toto:'+'n1='+`self.n1`+','+'n2='+`self.n2`

La classe toto définit une méthode spéciale appelée __str__. Voyons son usage dans le code de test suivant :

f1 = toto(10,20)
print f1    # affiche 'Instance de toto : n1=10,n2=20'

Il existe aussi une méthode analogue nommée __repr__. Veuillez vous reporter au guide des références pour plus de détails.

Tester la valeur de vérité avec __nonzero__

Cette méthode est appelée quand on veut savoir si l'objet est « vrai » ou « faux », par exemple quand on l'utilise dans un test. Elle doit retourner la valeur 0 ou 1. Quand cette méthode n'existe pas, __len__ est appelée. Si ni __nonzero__ ni __len__ n'existe, toutes les instances sont considérées vraies. Voici un exemple de ceci :

class foo:
	def __nonzero__(self):
		return 0
		
class baz:
	def __len__(self):
		return 0
		
class abc:
	pass
	

f1 = foo()
f2 = baz()
f3 = abc()
		
if (not f1): print 'foo: faux'  # affiche 'foo: faux'
if (not f2): print 'baz: faux'  # affiche 'baz: faux'
if (not f3): print 'abc: faux'  # n'affiche rien

La magie de __getitem__

Vous souhaitez que votre classe se comporte comme une liste ? La principale caractéristique d'une liste (ou d'un tuple, ou plus généralement une séquence) est qu'elle permet de faire de l'indexage. C'est à dire que l'on peut écrire des choses comme : print a[i]. Il existe une méthode spéciale nommée __getitem__ fait pour implanter l'indexage sur les objets définis par l'utilisateur. Par exemple :

class toto:
	def __init__(self, limit):
		self.limit = limit
		
	def __getitem__(self, key):
		if ((key > self.limit-1) or (key < -(self.limit-1))):
			raise IndexError
		else:
			return 2*key
			
f = toto(10)      # f se comporte comme un tableau de 20 éléments. 
print f[0], f[1]  # affiche 0, 2
print f[-3]       # affiche -6
print f[10]       # génère IndexError

D'autres méthodes existent pour implanter l'indexage : __setitem__, __delitem__, __getslice__, __setslice__ et __delslice__.

Accéder aux attributs avec __getattr__

__getattr__(self,nom) est appelé quand l'attribut « nom » est introuvable. Cette méthode devrait soit lever une exception AttributeError ou renvoyer un attribut calculé.

class toto:
	def __getattr__(self, name):
		return 'attribut introuvable'
		
f = toto()
f.n = 100
print f.n     # affiche 100
print f.m     # affiche 'attribut introuvable'

Notons qu'il existe aussi une fonction getattr(objet,nom). Ainsi, getattr(f, 'n') retourne 100, et getattr(f,'m') retourne la chaîne « attribut introuvable ». Ce mécanisme permet de réaliser très simplement des délégations :

class Boss:
	def __init__(self, délégué):
		self.d = délégué
		
	def credits(self):
		print "Je suis le grand chef, et j'ai fait moi même ces choses merveilleuses"
		
	def __getattr__(self, name):
		return getattr(self.d, name)
		
	
class Esclave:
	def work(self):
		print "Gasp, je suis l'esclave, et il a fallu que je fasse tout ça"
		
	
w = Esclave()	
b = Boss(w)
b.credits()  # affiche 'Je suis le grand chef, et j'ai fait moi même ces
	     # choses merveilleuses'
b.work()     # Affiche 'Gasp, je suis l'esclave, et il a fallu que je fasse
	     # tout ça'

Pour en savoir plus

La distribution vient avec une très bonne documentation (en anglais :), qui inclut un tutoriel, un guide de référence du langage et un guide de référence des bibliothèques. Si vous débutez en Python, vous devriez lire l'excellent tutoriel de Guido.Vous pouvez aussi parcourir les références du langage et les références des bibliothèques. Cet article a été traduit avec l'aide des références du langage.

Adaptation française de la Gazette Linux

L'adaptation française de ce document a été réalisée dans le cadre du Projet de traduction de la Gazette Linux.

Vous pourrez lire d'autres articles traduits et en apprendre plus sur ce projet en visitant notre site : http://www.traduc.org/Gazette_Linux.

Si vous souhaitez apporter votre contribution, n'hésitez pas à nous rejoindre, nous serons heureux de vous accueillir.