Historique de la question :
Les séquences sont l'un des concepts les plus anciens et fondamentaux en Python. Les exemples classiques incluent les listes (list), les chaînes (str), et les tuples (tuple). Un protocole spécial a été établi pour interagir avec les séquences : il est nécessaire d'implémenter les méthodes __getitem__ et __len__. Cela permet à l'objet de se comporter "comme une séquence" — supportant l'indexation, les tranches, le travail dans des boucles et même certaines fonctions standard.
Problème :
Sans la bonne implémentation de ces méthodes, une classe utilisateur ne pourra pas fonctionner avec des opérations d'indexation, des boucles for, ou des fonctions comme len(). Souvent, les développeurs débutants n'implémentent qu'une seule des méthodes, ne tiennent pas compte de la gestion des exceptions, ne gèrent pas le support des tranches (slice) et obtiennent un comportement incorrect ou inattendu.
Solution :
Il est nécessaire d'implémenter la méthode __getitem__(self, key) pour supporter l'indexation et les tranches, ainsi que __len__(self) pour travailler avec la fonction len() et une itérabilité correcte. Pour supporter les tranches, il faut distinguer le type de key dans __getitem__ et traiter correctement les objets de type slice.
Exemple de code :
def is_even(n): return n % 2 == 0 class EvenSequence: def __init__(self, size): self.size = size def __getitem__(self, index): if isinstance(index, slice): return [x for x in range(self.size)[index] if is_even(x)] if index < 0 or index >= self.size: raise IndexError('Index hors de portée') return index if is_even(index) else None def __len__(self): return self.size
Caractéristiques clés :
Peut-on se contenter de la méthode getitem pour que l'objet fonctionne comme une séquence ?
En partie. Si l'on implémente seulement __getitem__, on peut itérer sur l'objet avec for et indexer des éléments, mais len() ne fonctionnera pas.
Exemple de code :
class SeqOnlyGetitem: def __getitem__(self, index): if index >= 10: raise IndexError return index * 2 s = SeqOnlyGetitem() for x in s: print(x) # Fonctionne (itérable) # print(len(s)) # Erreur TypeError
Comment gérer les indices négatifs et que se passe-t-il si on ne les prend pas en compte ?
Les indices négatifs sont une caractéristique clé des séquences en Python. Si on ne les gère pas, l'objet se comporte de manière inattendue pour l'utilisateur.
class NegIndex: def __init__(self, data): self.data = data def __getitem__(self, index): if index < 0: index += len(self.data) return self.data[index]
Faut-il implémenter contains ou iter pour sa classe Sequence ?
Ce n'est pas obligatoire. Si __getitem__ et __len__ sont implémentés, la fonction in fonctionnera, et for les utilisera pour l'itération. La mise en œuvre de ces méthodes directement n'est généralement pas nécessaire, mais peut améliorer les performances.
Un développeur a implémenté seulement getitem pour sa classe uniquement pour des indices positifs. Le module a passé une partie des tests unitaires, mais lors de l'utilisation réelle, en essayant de récupérer un indice inexistant ou un indice négatif, tout s'est effondré.
Avantages :
Inconvénients :
L'équipe a implémenté les deux méthodes (getitem et len), a pris en compte les tranches, les indices négatifs, et a levé des exceptions appropriées. La classe finale a fonctionné dans tous les cas d'utilisation standard de Python.
Avantages :
Inconvénients :