5.7. Méthodes spéciales avancées

Il y a d'autres méthodes spéciales que __getitem__ et __setitem__. Certaines vous laissent émuler des fonctionnalité dont vous ignorez encore peut-être tout.

Cet exemple montre certaines des autres méthodes spéciales de UserDict.

Exemple 5.16. D'autres méthodes spéciales dans UserDict

    def __repr__(self): return repr(self.data)     1
    def __cmp__(self, dict):                       2
        if isinstance(dict, UserDict):            
            return cmp(self.data, dict.data)      
        else:                                     
            return cmp(self.data, dict)           
    def __len__(self): return len(self.data)       3
    def __delitem__(self, key): del self.data[key] 4
1 __repr__ est une méthode spéciale qui est appelée lorsque vous appelez repr(instance). La fonction repr est une fonction prédéfinie qui retourne une représentation en chaîne d'un objet. Elle fonctionne pour tout objet, pas seulement les instances de classes. En fait, vous êtes déjà familier de repr, même si vous l'ignorez. Dans la fenêtre interactive, lorsque vous tapez juste un nom de variable et faites Entrée, Python utilise repr pour afficher la valeur de la variable. Créez un dictionnaire d avec des données, puis faites print repr(d) pour le voir par vous même.
2 __cmp__ est appelé lorsque vous comparez des instances de classe. En général, vous pouvez comparer deux objets Python quels qu'ils soient, pas seulement des instances de classe, en utilisant ==. Il y a des règles qui définissent quand les types de données prédéfinis sont considérés égaux. Par exemple, les dictionnaires sont égaux quand ils ont les mêmes clés et valeurs, les chaînes sont égales quand elles ont la même longueur et contiennent la même séquence de caractères. Pour les instances de classe, vous pouvez définir la méthode __cmp__ et écrire la logique de comparaison vous-même et vous pouvez ensuite utiliser == pour comparer des instances de votre classe, Python appelera votre méthode spéciale __cmp__ pour vous.
3 __len__ est appelé lorsque vous appelez len(instance). La fonction len est une fonction prédéfinie qui retourne la longueur d'un objet. Elle fonctionne pour tout objet pour lequel il est envisageable de penser qu'il a une longueur. La len d'une chaîne est son nombre de caractères, la len d'un dictionnaire est son nombre de clés et la len d'une liste ou tuple est son nombre d'éléments. Pour les instances de classe, définissez la méthode __len__ et écrivez le calcul de longueur vous-même, puis appelez len(instance) et Python appelera votre méthode spéciale __len__ pour vous.
4 __delitem__ est appelé lorsque vous appelez del instance[key], ce qui, vous vous en rappelez peut-être, est le moyen de supprimer des éléments individuels d'un dictionnaire. Quand vous utilisez del sur une instance de classe, Python appelle la méthode spéciale __delitem__ pour vous.
NOTE
En Java, vous déterminez si deux variables de chaînes référencent la même zone mémoire à l'aide de str1 == str2. On appelle cela identité des objets et la syntaxe Python en est str1 is str2. Pour comparer des valeurs de chaînes en Java, vous utiliseriez str1.equals(str2), en Python, vous utiliseriez str1 == str2. Les programmeurs Java qui ont appris que le monde était rendu meilleur par le fait que == en Java fasse une comparaison par identité plutôt que par valeur peuvent avoir des difficultés à s'adapter au fait que Python est dépourvu d'un tel piège.

Vous trouvez peut-être que ça fait beaucoup de travail pour faire avec une classe ce qu'on peut faire avec un type de données prédéfini. Et c'est vrai que tout serait plus simple (et la classe UserDict serait inutile) si on pouvait hériter d'un type de données prédéfini comme un dictionnaire. Mais même si vous pouviez le faire, les méthodes spéciales seraient toujours utiles, car elles peuvent être utilisées dans n'importe quelle classe, pas seulement dans une classe enveloppe comme UserDict.

Les méthodes spéciales permettent à toute classe de stocker des paires clé-valeur comme un dictionnaire, simplement en définissant la méthode __setitem__. Toute classe peut se comporter comme une séquence, simplement en définissant la méthode __getitem__. Toute classe qui définit la méthode __cmp__ peut être comparée avec ==. Et si votre classe représente quelque chose qui a une longeur, ne créez pas une méthode GetLength, définissez la méthode __len__ et utilisez len(instance).

NOTE
Alors que les autres langages orientés objet ne vous laissent définir que le modèle physique d'un objet («cet objet a une méthode GetLength»), les méthodes spéciales de Python comme __len__ vous permettent de définir le modèle logique d'un objet («cet objet a une longueur»).

Il y a de nombreuses autres méthodes spéciales. Un ensemble de ces méthodes permet aux classes de se comporter comme des nombres, permettant l'addition, la soustraction et autres opérations arithmétiques sur des instances de classe (l'exemple type en est une classe représentant les nombres complexes, nombres ayant à la fois un composant réel et imaginaire). La méthode __call__ permet à une classe de se comporter comme une fonction, ce qui permet d'appeler une instance de classe directement. Il y a aussi d'autres méthodes spéciales permettant aux classes d'avoir des données attributs en lecture seule ou en écriture seule, nous en parlerons dans des chapitres à venir.

Pour en savoir plus sur les méthodes de classe spéciales