Page suivante   Page précédente Table des matières  

1. Attributs de méthodes spéciaux en Python

Pramode C E iclabs@vsnl.com

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.

1.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.

1.2 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.

1.3 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).

1.4 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.

1.5 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

1.6 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__ .

1.7 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'

1.8 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.

Copyright 2000, Pramode C E. Paru dans le numéro 54 de la Linux Gazette de Juin 2000.

Traduction française de Martin Quinson.


Page suivante   Page précédente Table des matières