2016-10-29 2 views
-2

In Bezug auf Iteratoren und Iterables nehmen (nur meine Beobachtung und bitte korrigieren Sie mich, wenn ich falsch bin):Methoden, die Iteratoren statt Iterables

  • Die meisten Konstrukteure (von arrayish-Typen) nehmen Iteratoren als Massen Konstruktor
  • Iteratoren werden explizit gemacht; oder durch x in x for....
  • Viele Methoden (vor allem, itertools) gibt Iteratoren (weil ihre Arbeitsplätze iterieren ist?)
  • Methoden, die Iterables Iteratoren nehmen nehmen. Stimmt das in allen Fällen?
  • Methoden, die Iteratoren nehmen nicht nehmen Iterables (Reverse nicht wahr ist)
  • Die einzige Methode, die einen Iterator ausdrücklich nimmt scheint next(..

Fragen zu sein:

  • Sind Gibt es andere Methoden, die Iteratoren verwenden?

  • Was sind die anderen Möglichkeiten, um Iteratoren mit Syntax zu erstellen? zB: x in x for...

  • Warum haben die Python-Ersteller next(.. als einzige Methode verlassen, die Iteratoren verwendet? Sie könnten es leicht zu einer Methode machen, die mit zusätzlichen Argumenten (Bedingungen) iterierbar ist?

Antwort

1

Die Sprache um Iteratoren und iterables ist ein wenig verwirrend. Die Hauptverwirrung kommt von dem Begriff "iterierbar", der eine Obermenge von "Iterator" sein kann oder nicht, abhängig davon, wie er verwendet wird.

Hier ist, wie ich die Dinge kategorisieren würde:

Ein iterable ist jedes Objekt, das auf durchlaufen werden können. Das heißt, es hat eine __iter__() Methode, die einen Iterator zurückgibt, oder sie ist mit Ganzzahlen indexierbar (die eine Ausnahme von IndexError auslöst, wenn sie außerhalb des Bereichs liegen), wodurch Python automatisch einen Iterator dafür erstellen kann. Dies ist eine sehr breite Kategorie. Ein Iterator ist ein Objekt, das dem Iteratorprotokoll folgt. Es hat eine __next__() Methode (buchstabiert next in Python 2), die das nächste Element ergibt, oder löst StopIteration Ausnahme aus, wenn keine weiteren Werte verfügbar sind. Ein Iterator muss auch eine __iter__()-Methode haben, die sich selbst zurückgibt, so dass alle Iteratoren auch iterierbar sind (da sie der oben angegebenen Definition von "iterable" entsprechen).

A nicht-Iterator iterable ist jede iterable die nicht ein Iterator ist. Dies ist oft das, was Menschen meinen, wenn sie den Begriff "iterierbar" im Gegensatz zu "Iterator" verwenden. Ein besserer Begriff in vielen Kontexten könnte "Sequenz" sein, aber das ist ein bisschen spezifischer (einige Nicht-Sequenz-Objekte sind Nicht-Iterator-Iterables, wie Wörterbücher, die eine Iteration über ihre Schlüssel erlauben). Das wichtige Merkmal dieser Kategorie von Objekten ist, dass Sie sie mehrmals durchlaufen können und die Iteratoren unabhängig voneinander arbeiten.

So zu versuchen, spezifische Fragen zu beantworten:

Es gibt selten einen guten Grund für jede Funktion speziell einen Iterator zu verlangen. Funktionen können normalerweise so ausgeführt werden, dass sie mit jeder Art von iterierbarem Argument funktionieren, entweder durch Aufruf von iter() im Argument, um einen Iterator zu erhalten, oder durch Verwendung einer for-Schleife, die den Iterator hinter den Kulissen erzeugt.

Das Gegenteil ist anders. Wenn eine Funktion einen iterierbaren Nicht-Iterator erfordert, muss das Argument möglicherweise mehrmals durchlaufen werden, sodass ein Iterator nicht ordnungsgemäß funktioniert. Funktionen in der Python-Standardbibliothek (und Built-Ins) haben jedoch selten eine solche Einschränkung. Wenn sie mehrere Male in einem iterierbaren Argument durchlaufen müssen, werden sie oft am Anfang in einen Sequenztyp (z. B. eine Liste) abgelegt, wenn es sich nicht bereits um eine Sequenz handelt.

Viele Funktionen geben Iteratoren zurück. Alle Generatorobjekte sind beispielsweise Iteratoren (sowohl diejenigen, die von Generatorfunktionen zurückgegeben werden, als auch solche, die mit Generatorausdrücken erzeugt werden). Dateiobjekte sind auch Iteratoren (obwohl sie das Iteratorprotokoll ein wenig verletzen, da Sie sie nach ihrer Erschöpfung mit ihrer seek()-Methode neu starten können). Und alle Funktionen und Typen im Modul itertools geben Iteratoren zurück, aber auch einige Builtins wie map() (in Python 3). Die next() Funktion ist in der Tat ungewöhnlich, da speziell ein Iterator benötigt wird. Dies liegt daran, dass es als Teil des Iterationsprotokolls selbst definiert ist. Es entspricht genau dem Aufruf der __next__() Methode auf dem Iterator, einfach besser zum Lesen. Es hat auch eine Zwei-Argument-Form, die die StopIteration Ausnahme unterdrückt, die andernfalls ausgelöst würde, wenn der Iterator erschöpft ist (es gibt stattdessen das Argument default zurück).

+0

Vielen Dank für die gründliche Erklärung. Nur um zu klären, list/tuple/range sind Sequenztyp. Nicht ein regulärer iterabler, sondern ein iterabler Nicht-Iterator. 'next (..' nimmt Iterator, der auch ein iterable ist. Aber es unterscheidet sich von einem anderen Typ von iterable (non-iterator iterable) = Sequenz = Liste/Tupel/Bereich. (Die spezifischen Details der anderen Unterschiede sind in Ihren Kommentaren) Es gibt mehr von ihnen, iterable, mit einer Verallgemeinerung: __iter __()? – theMobDog

+1

Ja, ich denke du hast es. Iterable ist der allgemeinste Begriff. Einige iterables sind Iteratoren, andere nicht. Ich nenne diejenigen, die sind nicht "non-iterator iterables", aber viele Leute nennen sie einfach "iterables", was zu Verwirrung führt (da es nicht klar ist, ob sie den allgemeineren Begriff oder die spezifischere Nicht-Iterator-Unterkategorie bedeuten). – Blckknght

Verwandte Themen