En Python, le protocole 'Sequence' définit une interface pour les objets qui peuvent être indexés et itérés, comme les listes ou les tuples. Historiquement, les séquences existent depuis presque les premières versions de Python pour prendre en charge les opérations naturelles sur les structures de données : indexation, tranches, itération des éléments.
Problème — pour qu'une classe utilisateur se comporte comme une séquence, il ne suffit pas d'avoir les méthodes iter et next. Un support complet du comportement de séquence nécessite des méthodes supplémentaires.
Solution — pour implémenter votre propre type de séquence, vous devez définir les méthodes getitem (nécessaire pour l'indexation et les tranches) et éventuellement len (pour len() et vérifier la longueur). Ainsi, l'objet prendra en charge l'itération, l'accès par index, le travail avec des tranches, ainsi que de nombreuses opérations standard de Python avec des séquences.
Exemple de code :
class MyCounter: def __init__(self, stop): self._stop = stop def __getitem__(self, index): if 0 <= index < self._stop: return index * 10 else: raise IndexError('Hors de portée') def __len__(self): return self._stop c = MyCounter(5) print(c[3]) # 30 print(len(c)) # 5 for x in c: print(x)
Caractéristiques clés :
Si j'implémente seulement iter et next, mon objet sera-t-il une séquence (Sequence) ?
Non. Un tel objet ne sera qu'itérable (iterable), mais pas une séquence. Il ne prendra pas en charge l'indexation, les tranches, les fonctions standard des objets semblables à des listes.
Est-il nécessaire d'implémenter getitem pour prendre en charge la boucle for ?
Ce n'est pas nécessaire. Si iter est implémenté, for fonctionnera. Mais s'il n'y a pas iter, l'interpréteur essaiera d'utiliser getitem, en commençant par l'index 0, jusqu'à ce qu'une IndexError se produise. Ainsi, pour une séquence, getitem est suffisant.
Peut-on implémenter getitem uniquement pour int, et pas pour slice ?
Techniquement, l'objet fonctionnera pour c[0], mais essayer de prendre une tranche c[1:4] échouera. Pour prendre en charge les tranches, getitem doit pouvoir traiter les objets de type slice (voir slice.indices et isinstance(key, slice)).
Exemple de code :
class S: def __getitem__(self, idx): if isinstance(idx, slice): return [x for x in range(idx.start or 0, idx.stop or 10, idx.step or 1)] return idx * 2
Ils ont implémenté une structure personnalisée en ne définissant que iter, pensant qu'ils pouvaient désormais utiliser des tranches et de l'indexation.
Avantages :
Inconvénients :
La classe implémente getitem avec prise en charge des tranches et des index int, ainsi que len.
Avantages :
Inconvénients :