Iteration in Python

Klicken Sie auf eine alle Schriftarten auf der Seite zu verkleinern.

Klicken Sie auf eine alle Schriftarten auf der Seite zu vergrößern.

Klicken Sie auf HC hohen Kontrastmodus zu umschalten. Wenn Sie die Maus über einige mutige Worte in hohem Kontrastmodus bewegen, werden verwandte Wörter automatisch hervorgehoben. Der Text wird in Schwarz und Weiß dargestellt.

Iterables vs. Iteratoren

In den breitest möglichen Bedingungen ist ein iterable etwas, das man durchlaufen kann, und ein Iterator ist, was der Interpreter verwendet die Iteration zu tun. Diese Beschreibung ist jedoch zu allgemein von genügend Wert zu sein. Die grundlegende Frage ist: Was ist der Dolmetscher tun, wenn Sie für i in s schreiben: in Ihrem Programm oder ein anderes Modul?

In der modernen Python, Iteration wird durch zwei völlig getrennte Mechanismen unterstützt. So ist die Antwort auf die Frage „Wie funktioniert der Dolmetscher über Objekte iterieren?“ hängt von der Gegenwart von spezifischen Methoden für das Objekt. Wenn das Objekt eine __iter __ () Methode hat, dann ist es iterable den neuen Stil Iteration Mechanismus. Ansonsten sucht der Interpreter für einen __getitem __ () -Methode, und wenn es einen findet, verwendet den alten Stil Iteration Mechanismus. Wenn weder Methode vorhanden ist, stellt sich der Dolmetscher eine Typeerror-Ausnahme, da das Objekt nicht iterable ist.

Wenn ein Objekt, o. keinen __iter __ () -Methode hat und Sie den Interpreter darüber iterieren sagen, initialisiert der Interpreter eine interne Variable ruft auf Null und wiederholt das __getitem __ () Methode des Objekts mit sukzessiv höheren Werten der internen Variablen. Aus der Sicht des Objekts, dann ist es, als ob es durch diesen Code manipuliert wurde:

BEOBACHTEN: Effektive Logik eines alten Stil für Schleife

In der Tat können Sie Ihre eigenen Klassen, deren Instanzen erstellen können auf diese Weise iteriert werden. Alles was Sie tun müssen, ist eine __getitem __ liefern (n) Methode, die eine Indexerror Ausnahme auslöst, wenn der Wert von n zu hoch ist. Angenommen, Sie mit fester Länge implementieren Sequenzen von Objekten gesucht. Sie könnten eine Funktion definieren, eine entsprechende Sequenz (Liste oder Tupel oder String) mit der erforderlichen Anzahl von Komponenten darin zu erstellen (so fls ( „*“, 12) zurückkehren würde „************ ". beispielsweise).

Alternativ können Sie eine fls Klasse, deren __init __ () -Methode hatte die gleiche Signatur wie die Funktion oben definieren. Erstellen Sie ein neues Projekt Python3_Lesson03 und weisen Sie auf Ihre Python3_Lessons Workingset. Dann erstellen fls.py im Python3_Lesson03 Projekt wie dargestellt.

CODE TYPE: fls.py

BEOBACHTEN: Ausgabe vom Laufen der fls Klasse

Also, für Iteration Zwecke können Sie sehen, dass die fls Objekte wie andere Sequenzen zu wirken scheinen, nur mit sehr langweilig Verhalten, da alle Elemente, die den gleich den einzigen Wert sein werden gezwungen, die __ __getitem () immer wieder sind derjenige, der übergeben wurde in zu __init __ (). Aber die Hauptsache ist, dass Sie ein wenig mehr über Python Iteration Mechanismus kennen. Nun versuchen, ein paar andere Fälle für eine interaktive Konsolensitzung selbst-erstellen und einige weitere fls interaktiv Objekte zu testen.

Denken Sie daran, müssen Sie die FLS-Klasse aus dem FLS-Modul, um Instanzen davon zu schaffen, um der Lage sein, importieren.

Die Iteration Mechanismus, der oben skizzierte ist alles sehr gut, wenn Sie iterieren nummerierten Elemente in einer Sequenz, aber es erstreckt sich nicht auf natürliche Weise Sammlungen wie Sets und dicts, die keine natürliche Ordnung für ihre Einzelteile angeben. Dicts, in der Tat, macht einen __getitem __ () -Methode, aber es nimmt einen Schlüsselwert und gibt den entsprechenden Punkt (unter der Annahme, dass ein Schlüssel mit diesem Wert vorhanden ist-wenn kein solcher Schlüssel ist, es wirft eine KeyError Ausnahme). Sets haben nicht einmal eine __getitem __ () Methode, da sie effektiv „item-weniger dicts“ sind.

Es war zu Fragen wie diese zu überwinden, die die „neuen Stils“ Iteration Protokoll definiert wurde. Sie haben gelernt, über dem der Dolmetscher für eine __iter __ () -Methode auf die Objekte sehen, die Sie durchlaufen. Wenn es findet __iter __ (). es nutzt sie einen Iterator aus dem iterable die Sie iterieren zu erstellen.

Der Iterator wird ein __next __ () -Methode, das ist eine Forderung der Iteration Protokoll. Jedes Mal, um die Schleife erhält der Dolmetscher den nächsten Wert für die iterable durch die Iterators __next __ () -Methode aufrufen. Auch hier können Sie dies vielleicht mehr verstehen leicht mit einer ungefähren Python entspricht ein for-Schleife über einen neuen Stil iterable:

BEOBACHTEN: Effektive Logik eines neuen Stils für Schleife

CODE TYPE: Geben Sie Folgendes in einer interaktiven Interpreter-Sitzung

Was ist der Unterschied zwischen den ersten for-Schleife und den zweiten? Schauen Sie sich die dir () Auflistung der lst, die eine Listeninstanz ist, und beachten Sie, dass es sowohl __iter __ () hat und __getitem __ () Methoden. Wenn der Interpreter iteriert über die Liste, ruft seine __iter __ () Methode ein neues Iterator erzeugt, eine komplette Folge von Werten ergibt, trifft jedes Mal, wenn eine for-Schleife.

Wir haben dann eine Liste Iteratorobjekt durch unsere Liste der __iter __ () -Methode manuell aufrufen. Beachten Sie, dass die Liste Iteratorobjekt auch eine __iter __ () Methode hat, und fügt eine __next __ () -Methode, aber es fehlt ein __getitem __ (). Die __iter __ () Methode des Iterators ist ziemlich verschieden von der Liste, aber:

BEOBACHTEN: __iter __ () Methode - in Python wäre es zu lesen:

Mit anderen Worten, iterieren jedesmal, wenn Sie über eine Liste (die ein iterable ist), erzeugt der Anruf an seinen __iter __ () -Methode ein neues Iterator, die ihren eigenen unabhängigen Staat hat. Der __iter __ des Iterators () Methode jedoch nicht schafft einen neuen Iterator, was bedeutet, dass die inneren und äußeren Schleifen sind den gleichen Iterator teilen. Dies wiederum bedeutet, dass die äußere Schleife der zweiten Iteration durch die Zeit versucht, zu beginnen, hat der Iterator bereits von der inneren Schleife und (zum zweiten Mal) ausgeschöpft wirft die StopIteration Ausnahme.

Erstellen Sie Ihre eigene Iteratoren

Anstatt nun ein Beispiel zu schaffen, werden wir es im nächsten Abschnitt erstellen. Zunächst werden wir einen Generator, erstellen und dann werden wir eine äquivalente Iterator bauen.

Generatoren: Vermeiden Erstellung von großen Folgen

Die Iteration Protokoll oben auch mit sogenannten Generator-Funktionen ins Spiel kommt, diskutiert. Der einzige offensichtliche Unterschied zwischen einer Generatorfunktion und der regulären Art, die Sie mit, bevor gehandelt haben, ist das Aussehen der Ausbeute Schlüsselwort in dem Funktionskörper. Also, was ist der Unterschied zwischen einer regulären Funktion und einer Generatorfunktion?

Die Antwort ist, dass eine Generatorfunktion Aufruf erzeugt eine spezielle Art von Iterator-Objekt (ein „Generator“). Die Funktion Namensraum wird mit den Argumentwerten erstellt und initialisiert. Der Funktionscode beginnt erst mit dem ersten Aufruf der Generator des __next __ () Methode ausführt. Die Ausführung wird fortgesetzt, bis eine Ausbeute Ausdruck ausgewertet wird: der Wert des Ausdrucks folgenden Ausbeute der Wert des __next __ wird () Methode aufrufen. Sie können dies mit einer sehr einfachen Generatorfunktion in einer interaktiven Sitzung sehen.

CODE TYPE: Geben Sie den folgenden Code in einem interaktiven Interpreter Fenster

obwohl g () ist eine Generatorfunktion, wenn Sie die Dolmetscher zu fragen Sie keinen Unterschied zu einer anderen Funktion sehen. Nennt es erzeugt ein Generator-Objekt, aber, und das dir () Auflistung zeigt, dass es die notwendigen Methoden für einen Iterator hat. Aufrufen der __next __ des Objekts () Methode gibt das Ergebnis der nächsten Ausbeute Expression in den Codekörper der Funktion.

Wenn die Funktion endet, bevor eine Ausbeute Expression stoßen (entweder durch eine return-Anweisung ausgeführt wird oder die unteren Abwurf), der __next __ () Methodenaufruf wirft eine StopIteration Ausnahme wie jeder anderer Iterator. Beachten Sie auch, dass, sobald der Generator StopIteration Ausnahmen zu erhöhen beginnt, wenn __next __ () aufgerufen wird, geht es so für jedes weitere tun anruf der Iterator ist erschöpft.

Vorteile der Generator-Funktionen

Das ist wirklich praktisch, was über Generator-Funktionen ist, dass sie ermöglicht es Ihnen, alle Arten von komplexen Berechnungen durchzuführen, um die Werte in einer Sequenz zu produzieren, aber der Code, können verbraucht (nutzt) werden diese Werte vollständig vom Generator getrennt, die sie erzeugen. Die Werte werden in einem einfachen for-Schleife-oder irgendeinem anderen ähnlichen iterativen Kontext in Python, wie zum Beispiel einer Liste Verständnis verbraucht.

Nicht nur, dass sie Ihren Code einfacher machen, indem die Produktion und den Verbrauch von Sequenzen zu trennen, aber Generatoren können Sie Sequenzwerte einer nach dem anderen erzeugen, wie sie verbraucht werden. Es besteht keine Notwendigkeit, eine Liste oder Tupel bauen sie in speichern, was bedeutet, dass Ihre Programme weniger Speicher verwenden und arbeiten schneller (obwohl diese Vorteile wirklich nicht viel Unterschied machen, es sei denn, die Anzahl der Objekte groß).

Eine einfache Generator-Funktion

Angenommen, Sie müssen Sequenzen durch eine Liste bestimmt produzieren, sondern müssen das erste Listenelement einmal wiederholen, die zweimal pro Sekunde, und so weiter. Gegeben, so eine Liste [2, 4, 6]. die resultierende Sequenz wäre 2, 4, 4, 6, 6, 6 der einen Generator Lassen schreiben, die solche Sequenzen produziert. Zunächst aber werden wir Tests schreiben, um sicherzustellen, dass unsere Generatorfunktion arbeitet. Erstellen testgen.py in Ihrem Python3_Lesson03 / src Verzeichnis wie angegeben:

CODE TYPE: testgen.py

Wie üblich, beginnen wir mit einer einfachen Stub-Funktion, um sicherzustellen, dass die Tests fehlschlagen. Erstellen Sie jetzt gen123.py in Ihrem Python3_Lesson03 / src Verzeichnis wie angegeben:

CODE TYPE: gen123.py

Ein Iterator Equivalent des Generators

Wie Sie oben gelernt haben, ist es auch möglich, Klassen zu schreiben, der die Iteration Protokoll gehorchen. Sie werden diese Lektion am Ende durch einen Iterator Äquivalent der Generatorfunktion über das Schreiben. Da Sie es genau die gleichen wie die gen123 Generatoren durchführen möchten, können Sie die gleichen Tests verwenden, um seinen Betrieb-die zu überprüfen, ist einer der Vorteile eines Test-Driven-Umgebung ist! Die neue Komponente sollte idealerweise ein „Drop-in-Ersatz“ sein für die Generatorfunktion. Erstellen class123.py in Ihrem Python3_Lesson03 / src Verzeichnis wie angegeben:

CODE TYPE: class123.py

Dieser Code ist wesentlich komplexer. Dies sollte nicht überraschen, da Generator-Funktionen entwickelt wurden, diese Art von Problem sauber zu lösen und einfach.

Statt die Generatorfunktion aufzurufen, wird die Testroutine jetzt Ihre Iterator Klasse nennen (was, werden Sie feststellen, hat den gleichen Namen). Dies bewirkt, dass seine __init __ () Methode ausgeführt werden, und die Liste der Werte wird als eine Instanz-Variablen gespeichert. Zwei weitere Instanzvariablen werden initialisiert: eine Spur zu halten, von denen Artikel zur Zeit ausgegeben werden, und die andere, um zu verfolgen, wie oft der aktuelle Wert erzeugt worden ist.

Die ganze Magie, natürlich, findet in dem __next __ () -Methode. Zunächst überprüft er, ob es Zeit ist, auf das nächste Element der Werteliste (zunächst die Artikelnummer und die Zählung werden, um zu gewährleisten, dass dieser Zweig auf dem ersten Aufruf actioned ist) zu bewegen. Wenn ja, wird die val Instanzvariable abgerufen.

Wenn keine Werte mehr vorhanden sind, stellt das Verfahren eine StopIteration Ausnahme um die Schleife zu beenden. Beachten Sie sorgfältig, dass diese Aktion wiederholt einmal werden kann das Verfahren die Ausnahme zu erhöhen beginnt, sollte es für jeden nachfolgenden Aufruf erhöht werden.

Sobald der richtige Positionswert festgelegt wird, wird der Zähler erhöht und der Wert wird als Ergebnis des Aufrufs zurückgegeben.

das Modul zu testen ist einfach. So stellen Sie die folgende Änderung des Testprogramms:

Code zu bearbeiten: testgen.py

Nachdem das neue Stil Iteration Protokoll in Python angenommen wurde, beobachtete einer der Entwickler, dass es sehr nützlich sein, wäre in der Lage sein, Ausdrücke zu schreiben, die sie mit der Iteration Comprehensions zur Liste ähnlich waren (für) und Auswahl (if) Elemente Ausdrücke zu erzeugen dass ihre Ergebnisse erzeugt, anstatt eine Liste zu erzeugen. Die Überlegung dahinter ist, genauso wie die Gründe für Standard-Generatoren schöpf die Objekte eins nach dem anderen „on demand“ ist platzsparender und ist wahrscheinlich Programme zu beschleunigen, mit großen Folgen beschäftigen erheblich, sowie die Verringerung ihrer Erinnerung Anforderungen.

Die Syntax eines Generators Ausdruck ist die gleiche wie für Listenkomprehensionen (in einem früheren Kurs gelernt), aber mit Klammern statt Klammern. Weil sie Generatoren sind aber sehen Sie nur die einzelnen Werte, wenn man sie innerhalb einer Iteration verbrauchen. Erfahren Sie ein wenig mehr über sie, indem sie in einer interaktiven Interpreter-Sitzung zu spielen.

Beachten Sie, dass der Generator Ausdrücke Iteratoren sind, aber nicht Iterables: sobald man über sie iteriert haben sie erschöpft sind, und jeder weitere Versuch, den Ausdruck iterieren hebt sofort StopIteration. Beachten Sie auch, dass Sie eine neue integrierte Funktion in dieser Sitzung verwendet. nächstes (o) Der Aufruf ist so ziemlich gleichwertig o dem Aufruf .__ nächsten __ (). bis auf die Erhebung einer StopIteration Ausführung, wenn keine Werte mehr zur Verfügung stehen.

Sie wissen jetzt viel mehr über die Art und Weise Python iteriert über Objekte, als Sie früher getan haben. effektiv Mit etwas Glück können dieses Wissen Sie Objekte erstellen, die Sie Ihre Probleme lösen helfen.

Wenn Sie die Lektion beenden, kehren Sie zu dem Lehrplan und die Tests und Projekte abzuschließen.

In Verbindung stehende Artikel