In Python definiert das 'Sequence'-Protokoll eine Schnittstelle für Objekte, die indiziert und iteriert werden können, beispielsweise Listen oder Tupel. Historisch gesehen wurden Sequenzen praktisch in den ersten Versionen von Python eingeführt, um natürliche Operationen mit Datenstrukturen zu unterstützen: Indizierung, Slicing, Iteration durch Elemente.
Problem – Damit eine benutzerdefinierte Klasse sich wie eine Sequenz verhält, sind die Methoden iter und next nicht ausreichend. Für die vollständige Unterstützung des Sequence-Verhaltens sind zusätzliche Methoden erforderlich.
Lösung – Um einen eigenen Sequenztyp zu implementieren, müssen die Methoden getitem (notwendig für Indizierung und Slicing) und optional len (für len() und Überprüfung der Länge) definiert werden. So wird das Objekt die Iteration, den Indexzugriff, das Arbeiten mit Slices sowie viele Standardoperationen von Python mit Sequenzen unterstützen.
Beispielcode:
class MyCounter: def __init__(self, stop): self._stop = stop def __getitem__(self, index): if 0 <= index < self._stop: return index * 10 else: raise IndexError('Out of range') def __len__(self): return self._stop c = MyCounter(5) print(c[3]) # 30 print(len(c)) # 5 for x in c: print(x)
Hauptmerkmale:
Wenn ich nur iter und next implementiere, wird mein Objekt eine Sequenz (Sequence)?
Nein. Ein solches Objekt wird nur iterierbar (iterable) sein, aber keine Sequenz. Es wird keine Indizierung, Slicing und keine Standardfunktionen von list-ähnlichen Objekten unterstützen.
Ist es notwendig, getitem zu implementieren, um eine for-Schleife zu unterstützen?
Nicht unbedingt. Wenn iter implementiert ist, funktioniert for. Wenn kein iter vorhanden ist, versucht der Interpreter jedoch, getitem ab Index 0 zu verwenden, bis ein IndexError auftritt. Daher reicht für eine Sequenz getitem aus.
Kann ich getitem nur für int und nicht für slice implementieren?
Technisch wird das Objekt für c[0] funktionieren, aber der Versuch, einen Slice c[1:4] zu nehmen, wird fehlschlagen. Um Slices zu unterstützen, muss getitem in der Lage sein, Objekte vom Typ slice zu verarbeiten (siehe slice.indices und isinstance(key, slice)).
Beispielcode:
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
Sie haben eine benutzerdefinierte Struktur implementiert, indem Sie nur iter definiert haben, in der Annahme, dass Sie nun Slices und Indizierung verwenden können.
Vorteile:
Nachteile:
Die Klasse implementiert getitem mit Unterstützung für Slicing und int-Indices sowie len.
Vorteile:
Nachteile: