In Python ist die Schnittstelle eines Iterablen eine Teilmenge der iterator interface. Dies hat den Vorteil, dass sie in vielen Fällen gleich behandelt werden können. Es gibt jedoch einen wichtigen semantischen Unterschied zwischen den beiden, da für eine iterierbare __iter__
ein neues Iteratorobjekt und nicht nur self
zurückgegeben wird. Wie kann ich testen, ob ein Iterable wirklich ein Iterator ist und kein Iterator? Konzeptuell verstehe ich iterables als Sammlungen, während ein Iterator nur die Iteration verwaltet (d. H. Die Position verfolgt), aber keine Sammlung selbst ist.Wie kann ich den Unterschied zwischen einem Iterator und einem Iterablen unterscheiden?
Der Unterschied ist zum Beispiel wichtig, wenn man mehrere Male wiederholen möchte. Wenn ein Iterator angegeben wird, funktioniert die zweite Schleife nicht, da der Iterator bereits verbraucht ist und direkt StopIteration
auslöst.
Es ist verlockend, für eine next
Methode zu testen, aber das scheint gefährlich und irgendwie falsch. Sollte ich nur überprüfen, dass die zweite Schleife leer war?
Gibt es eine Möglichkeit, einen solchen Test auf eher pythische Weise durchzuführen? Ich weiß, dass das klingt wie ein klassischer Fall von LBYL gegen EAFP, also sollte ich vielleicht einfach aufgeben? Oder fehlt mir etwas?
Edit: S.Lott sagt in seiner Antwort unten, dass dies in erster Linie ein Problem zu wollen mehr Durchgänge über den Iterator zu tun, und das sollte man nicht tun in erster Linie. In meinem Fall sind die Daten jedoch sehr groß und müssen je nach Situation mehrfach für die Datenverarbeitung übergeben werden (dazu gibt es absolut keinen Weg).
Das iterierbare Element wird auch vom Benutzer bereitgestellt, und für Situationen, in denen ein einziger Durchgang ausreicht, arbeitet es mit einem Iterator (der z. B. der Einfachheit halber von einem Generator erzeugt wird). Aber es wäre schön, sich gegen den Fall abzusichern, dass ein Benutzer nur einen Iterator bereitstellt, wenn mehrere Durchgänge benötigt werden.
Bearbeiten 2: Eigentlich ist dies ein sehr schönes Beispiel für Abstract Base Classes. Die __iter__
Methoden in einem Iterator und einem iterablen haben denselben Namen, sind aber semantisch verschieden! So hasattr
ist nutzlos, aber isinstance
bietet eine saubere Lösung.
Wow, das scheint die Antwort zu sein, nach der ich gesucht habe, danke! Ich werde etwas warten, bevor ich es akzeptiere, falls jemand ein Problem damit aufzeigen kann. – nikow
Nun, das Problem ist ein "verschwendeter" Aufruf an obj .__ iter __(), aber ich sehe keinen anderen zuverlässigen Weg, es zu tun. – vartec
Obwohl ich kein Gegenbeispiel kenne, funktioniert das nicht * garantiert *. – tzot