Python "for" -Schleifen (Definite Iteration)

Python "for" -Schleifen (Definite Iteration)

Dieses Tutorial zeigt Ihnen, wie Siedefinite iteration mit einer Pythonfor-Schleife ausführen.

Inprevious tutorial in dieser Einführungsreihe haben Sie Folgendes gelernt:

  • Die wiederholte Ausführung desselben Codeblocks wird immer wieder alsiteration bezeichnet.

  • Es gibt zwei Arten von Iterationen:

    • Definite Iteration, bei der die Anzahl der Wiederholungen explizit im Voraus angegeben wird

    • Indefinite Iteration, bei der der Codeblock ausgeführt wird, bis eine bestimmte Bedingung erfüllt ist

  • In Python wird eine unbestimmte Iteration mit einerwhile-Schleife durchgeführt.

In diesem Tutorial wird Folgendes behandelt:

  • Sie beginnen mit einem Vergleich einiger verschiedener Paradigmen, die von Programmiersprachen verwendet werden, um eine bestimmte Iteration zu implementieren.

  • Dann lernen Sieiterables unditerators kennen, zwei Konzepte, die die Grundlage für eine bestimmte Iteration in Python bilden.

  • Schließlich binden Sie alles zusammen und lernen diefor-Schleifen von Python kennen.

Free Bonus:Click here to get access to a chapter from Python Tricks: The Book zeigt Ihnen die Best Practices von Python anhand einfacher Beispiele, die Sie sofort anwenden können, um schöneren + Pythonic-Code zu schreiben.

Ein Überblick über bestimmte Iterationen in der Programmierung

Bestimmte Iterationsschleifen werden häufig alsfor-Schleifen bezeichnet, dafor das Schlüsselwort ist, mit dem sie in fast allen Programmiersprachen, einschließlich Python, eingeführt werden.

In der Vergangenheit haben Programmiersprachen einige verschiedene Varianten derfor-Schleife angeboten. Diese werden in den folgenden Abschnitten kurz beschrieben.

Numerische Bereichsschleife

Die grundlegendstefor-Schleife ist eine einfache numerische Bereichsanweisung mit Start- und Endwerten. Das genaue Format variiert je nach Sprache, sieht aber normalerweise so aus:

for i = 1 to 10
    

Hier wird der Körper der Schleife zehnmal ausgeführt. Die Variablei nimmt bei der ersten Iteration den Wert1, bei der zweiten2 usw. an. Diese Art vonfor-Schleife wird in den Sprachen BASIC, Algol und Pascal verwendet.

Schleife mit drei Ausdrücken

Eine andere Form derfor-Schleife, die von der Programmiersprache C populär gemacht wird, besteht aus drei Teilen:

  • Eine Initialisierung

  • Ein Ausdruck, der eine Endbedingung angibt

  • Eine Aktion, die am Ende jeder Iteration ausgeführt werden soll.

Dieser Typ hat die folgende Form:

for (i = 1; i <= 10; i++)
    

Technical Note: In der Programmiersprache C erhöhti++ die Variablei. Es entspricht ungefähri += 1 in Python.

Diese Schleife wird wie folgt interpretiert:

  • Initialisieren Siei auf1.

  • Setzen Sie die Schleife so lange fort, wiei <= 10.

  • Erhöhen Siei nach jeder Schleifeniteration um1.

for-Schleifen mit drei Ausdrücken sind beliebt, da die für die drei Teile angegebenen Ausdrücke fast alles sein können. Dies hat also einiges mehr Flexibilität als die oben gezeigte einfachere Form des numerischen Bereichs. Diesefor-Schleifen sind auch in den Sprachen C ++, Java, PHP und Perl enthalten.

Sammlungsbasierte oder Iterator-basierte Schleife

Diese Art von Schleife durchläuft eine Sammlung von Objekten, anstatt numerische Werte oder Bedingungen anzugeben:

for i in 
    

Jedes Mal, wenn die Schleife durchlaufen wird, nimmt die Variablei den Wert des nächsten Objekts in<collection> an. Diese Art derfor-Schleife ist wohl die allgemeinste und abstrakteste. Perl und PHP unterstützen diese Art von Schleife ebenfalls, sie wird jedoch durch das Schlüsselwortforeach anstelle vonfor eingeführt.

Further Reading: Auf der Wikipedia-Seite vonFor loop finden Sie einen detaillierten Überblick über die Implementierung einer bestimmten Iteration in verschiedenen Programmiersprachen.

Die Pythonfor-Schleife

Von den oben aufgeführten Schleifentypen implementiert Python nur die letzte: sammlungsbasierte Iteration. Auf den ersten Blick mag das wie ein roher Deal erscheinen, aber seien Sie versichert, dass Pythons Implementierung einer bestimmten Iteration so vielseitig ist, dass Sie sich nicht betrogen fühlen!

In Kürze werden Sie sich eingehend mit derfor-Schleife von Python befassen. Beginnen wir zunächst mit einem kurzen Prototyp und einem Beispiel, um uns kennenzulernen.

Diefor-Schleife von Python sieht folgendermaßen aus:

for  in :
    

<iterable> ist eine Sammlung von Objekten, z. B. eine Liste oder ein Tupel. Die<statement(s)> im Schleifenkörper werden wie bei allen Python-Steuerstrukturen durch Einrückung gekennzeichnet und für jedes Element in<iterable> einmal ausgeführt. Die Schleifenvariable<var> nimmt jedes Mal durch die Schleife den Wert des nächsten Elements in<iterable> an.

Hier ist ein repräsentatives Beispiel:

>>>

>>> a = ['foo', 'bar', 'baz']
>>> for i in a:
...     print(i)
...
foo
bar
baz

In diesem Beispiel ist<iterable> die Listea und<var> die Variablei. Jedes Mal, wenn die Schleife durchlaufen wird, nimmti ina ein aufeinanderfolgendes Element an, sodassprint() die Werte'foo','bar' und'baz' anzeigt , beziehungsweise. Eine solchefor-Schleife ist die pythonische Methode, um die Elemente in einer Iterierbarkeit zu verarbeiten.

Aber was genau ist eine iterable? Bevor Sie die Schleifen vonforweiter untersuchen, sollten Sie sich eingehender mit den Iterables in Python befassen.

Iterables

In Python bedeutetiterable, dass ein Objekt in der Iteration verwendet werden kann. Der Begriff wird verwendet als:

  • An adjective: Ein Objekt kann als iterierbar beschrieben werden.

  • A noun: Ein Objekt kann als iterierbar charakterisiert werden.

Wenn ein Objekt iterierbar ist, kann es an die integrierte Python-Funktioniter() übergeben werden, die etwas zurückgibt, das alsiterator bezeichnet wird. Ja, die Terminologie wiederholt sich ein bisschen. Halte durch. Am Ende klappt alles.

Jedes der Objekte im folgenden Beispiel ist iterierbar und gibt eine Art Iterator zurück, wenn es aniter() übergeben wird:

>>>

>>> iter('foobar')                             # String


>>> iter(['foo', 'bar', 'baz'])                # List


>>> iter(('foo', 'bar', 'baz'))                # Tuple


>>> iter({'foo', 'bar', 'baz'})                # Set


>>> iter({'foo': 1, 'bar': 2, 'baz': 3})       # Dict

Diese Objekttypen sind dagegen nicht iterierbar:

>>>

>>> iter(42)                                   # Integer
Traceback (most recent call last):
  File "", line 1, in 
    iter(42)
TypeError: 'int' object is not iterable

>>> iter(3.1)                                  # Float
Traceback (most recent call last):
  File "", line 1, in 
    iter(3.1)
TypeError: 'float' object is not iterable

>>> iter(len)                                  # Built-in function
Traceback (most recent call last):
  File "", line 1, in 
    iter(len)
TypeError: 'builtin_function_or_method' object is not iterable

Alle bisher angetroffenen Datentypen, bei denen es sich um Sammlungs- oder Containertypen handelt, können iteriert werden. Dazu gehören die Typenstring,list,tuple,dict,set undfrozenset.

Dies sind jedoch keineswegs die einzigen Typen, über die Sie iterieren können. Viele Objekte, die in Python integriert oder in Modulen definiert sind, sind iterierbar. Beispielsweise sind geöffnete Dateien in Python iterierbar. Wie Sie bald im Tutorial zu Datei-E / A sehen werden, liest das Durchlaufen eines geöffneten Dateiobjekts Daten aus der Datei.

Tatsächlich kann fast jedes Objekt in Python iterierbar gemacht werden. Auch benutzerdefinierte Objekte können so gestaltet werden, dass sie wiederholt werden können. (Wie das geht, erfahren Sie im kommenden Artikel zur objektorientierten Programmierung.)

Iteratoren

Okay, jetzt wissen Sie, was es bedeutet, dass ein Objekt iterierbar ist, und Sie wissen, wie Sieiter() verwenden, um einen Iterator daraus zu erhalten. Was können Sie damit tun, wenn Sie einen Iterator haben?

Ein Iterator ist im Wesentlichen ein Wertproduzent, der aufeinanderfolgende Werte aus seinem zugeordneten iterierbaren Objekt liefert. Die eingebaute Funktionnext() wird verwendet, um den nächsten Wert aus dem Iterator zu erhalten.

Hier ist ein Beispiel mit derselben Liste wie oben:

>>>

>>> a = ['foo', 'bar', 'baz']

>>> itr = iter(a)
>>> itr


>>> next(itr)
'foo'
>>> next(itr)
'bar'
>>> next(itr)
'baz'

In diesem Beispiel ista eine iterierbare Liste unditr ist der zugeordnete Iterator, der mititer() erhalten wird. Jedernext(itr)-Aufruf erhält den nächsten Wert vonitr.

Beachten Sie, wie ein Iterator seinen Status intern beibehält. Es weiß, welche Werte bereits erhalten wurden. Wenn Sie alsonext() aufrufen, weiß es, welcher Wert als nächstes zurückgegeben werden soll.

Was passiert, wenn dem Iterator die Werte ausgehen? Lassen Sie uns den obigen Iterator noch einmalnext()aufrufen:

>>>

>>> next(itr)
Traceback (most recent call last):
  File "", line 1, in 
    next(itr)
StopIteration

Wenn bereits alle Werte eines Iterators zurückgegeben wurden, löst ein nachfolgender Aufruf vonnext()eine Ausnahme vonStopIterationaus. Alle weiteren Versuche, Werte vom Iterator abzurufen, schlagen fehl.

Sie können nur Werte von einem Iterator in eine Richtung erhalten. Sie können nicht rückwärts gehen. Es gibt keineprev()-Funktion. Sie können jedoch zwei unabhängige Iteratoren für dasselbe iterierbare Objekt definieren:

>>>

>>> a
['foo', 'bar', 'baz']

>>> itr1 = iter(a)
>>> itr2 = iter(a)

>>> next(itr1)
'foo'
>>> next(itr1)
'bar'
>>> next(itr1)
'baz'

>>> next(itr2)
'foo'

Selbst wenn sich der Iteratoritr1 bereits am Ende der Liste befindet, befindet sichitr2 immer noch am Anfang. Jeder Iterator behält seinen eigenen internen Zustand bei, unabhängig vom anderen.

Wenn Sie alle Werte gleichzeitig von einem Iterator abrufen möchten, können Sie die integrierte Funktionlist()verwenden. list() verwendet unter anderem einen Iterator als Argument und gibt eine Liste zurück, die aus allen Werten besteht, die der Iterator geliefert hat:

>>>

>>> a = ['foo', 'bar', 'baz']
>>> itr = iter(a)
>>> list(itr)
['foo', 'bar', 'baz']

In ähnlicher Weise geben die integrierten Funktionentuple() undset() ein Tupel bzw. eine Menge von allen Werten zurück, die ein Iterator liefert:

>>>

>>> a = ['foo', 'bar', 'baz']

>>> itr = iter(a)
>>> tuple(itr)
('foo', 'bar', 'baz')

>>> itr = iter(a)
>>> set(itr)
{'baz', 'foo', 'bar'}

Es ist nicht unbedingt ratsam, sich daran zu gewöhnen. Ein Teil der Eleganz von Iteratoren ist, dass sie "faul" sind. Das bedeutet, dass beim Erstellen eines Iterators nicht alle Elemente generiert werden, die er gerade dann liefern kann. Es wartet, bis Sie mitnext() nach ihnen fragen. Elemente werden erst erstellt, wenn sie angefordert werden.

Wenn Sielist(),tuple() oder ähnliches verwenden, zwingen Sie den Iterator, alle seine Werte gleichzeitig zu generieren, damit sie alle zurückgegeben werden können. Wenn die Gesamtzahl der vom Iterator zurückgegebenen Objekte sehr groß ist, kann dies lange dauern.

Tatsächlich ist es möglich, in Python einen Iterator zu erstellen, der eine endlose Reihe von Objekten zurückgibt. (Wie das geht, erfahren Sie in den kommenden Tutorials zu Generatorfunktionen unditertools.) Wenn Sie versuchen, alle Werte auf einmal von einem endlosen Iterator abzurufen, führt das Programmhang aus.

Die Eingeweide der Pythonfor-Schleife

Sie haben nun alle Konzepte kennengelernt, die Sie benötigen, um die Funktionsweise derfor-Schleife von Python vollständig zu verstehen. Bevor wir fortfahren, überprüfen wir die relevanten Begriffe:

Term Bedeutung

Wiederholung

Der Prozess des Durchlaufens der Objekte oder Elemente in einer Sammlung

Wiederholbar

Ein Objekt (oder das Adjektiv, mit dem ein Objekt beschrieben wird), über das iteriert werden kann

Iterator

Das Objekt, das aufeinanderfolgende Elemente oder Werte aus seiner zugeordneten iterierbaren Datei erzeugt

iter()

Die integrierte Funktion, mit der ein Iterator von einem Iterator abgerufen wird

Betrachten Sie nun noch einmal die einfachefor-Schleife, die zu Beginn dieses Tutorials vorgestellt wurde:

>>>

>>> a = ['foo', 'bar', 'baz']
>>> for i in a:
...     print(i)
...
foo
bar
baz

Diese Schleife kann vollständig anhand der Konzepte beschrieben werden, die Sie gerade kennengelernt haben. Um die Iteration auszuführen, die diesefor-Schleife beschreibt, führt Python Folgendes aus:

  • Ruftiter() auf, um einen Iterator füra zu erhalten

  • Ruftnext() wiederholt auf, um nacheinander jedes Element vom Iterator zu erhalten

  • Beendet die Schleife, wennnext() die AusnahmeStopIterationauslöst

Der Schleifenkörper wird einmal für die Rückgabe jedes Elementsnext()ausgeführt, wobei die Schleifenvariablei für jede Iteration auf das angegebene Element gesetzt wird.

Diese Abfolge von Ereignissen ist in der folgenden Abbildung zusammengefasst:

Vielleicht scheint dies eine Menge unnötiger Affengeschäfte zu sein, aber der Nutzen ist beträchtlich. Python behandelt das Durchlaufen aller Iterables genau so, und in Python gibt es eine Fülle von Iterables und Iteratoren:

  • Viele integrierte Objekte und Bibliotheksobjekte sind iterierbar.

  • Es gibt ein Standardbibliotheksmodul namensitertools, das viele Funktionen enthält, die iterable zurückgeben.

  • Benutzerdefinierte Objekte, die mit der objektorientierten Funktion von Python erstellt wurden, können iterierbar gemacht werden.

  • Python verfügt über ein Konstrukt namens Generator, mit dem Sie auf einfache und unkomplizierte Weise Ihren eigenen Iterator erstellen können.

In dieser Serie erfahren Sie mehr über all das oben Genannte. Sie können alle das Ziel einerfor-Schleife sein, und die Syntax ist auf der ganzen Linie gleich. Es ist elegant in seiner Einfachheit und äußerst vielseitig.

Durch ein Wörterbuch iterieren

Sie haben bereits gesehen, dass ein Iterator aus einem Wörterbuch mititer() abgerufen werden kann. Sie wissen also, dass Wörterbücher iterierbar sein müssen. Was passiert, wenn Sie ein Wörterbuch durchlaufen? Mal sehen:

>>>

>>> d = {'foo': 1, 'bar': 2, 'baz': 3}
>>> for k in d:
...     print(k)
...
foo
bar
baz

Wie Sie sehen können, wird die Schleifenvariable den Schlüsseln des Wörterbuchs zugewiesen, wenn einefor-Schleife ein Wörterbuch durchläuft.

Um auf die Wörterbuchwerte innerhalb der Schleife zuzugreifen, können Sie wie gewohnt mit dem Schlüssel eine Wörterbuchreferenz erstellen:

>>>

>>> for k in d:
...     print(d[k])
...
1
2
3

Sie können die Werte eines Wörterbuchs auch direkt mit.values() durchlaufen:

>>>

>>> for v in d.values():
...     print(v)
...
1
2
3

Tatsächlich können Sie sowohl die Schlüssel als auch die Werte eines Wörterbuchs gleichzeitig durchlaufen. Dies liegt daran, dass die Schleifenvariable einerfor-Schleife nicht nur auf eine einzelne Variable beschränkt ist. Es kann sich auch um ein Tupel handeln. In diesem Fall werden die Zuweisungen aus den Elementen in der Iterable mithilfe des Packens und Entpackens vorgenommen, genau wie bei einer Zuweisungsanweisung:

>>>

>>> i, j = (1, 2)
>>> print(i, j)
1 2

>>> for i, j in [(1, 2), (3, 4), (5, 6)]:
...     print(i, j)
...
1 2
3 4
5 6

Wie im Tutorial zu Pythondictionaries erwähnt, gibt die Wörterbuchmethode.items() effektiv eine Liste von Schlüssel / Wert-Paaren als Tupel zurück:

>>>

>>> d = {'foo': 1, 'bar': 2, 'baz': 3}

>>> d.items()
dict_items([('foo', 1), ('bar', 2), ('baz', 3)])

Die pythonische Methode zum Durchlaufen eines Wörterbuchs, das sowohl auf die Schlüssel als auch auf die Werte zugreift, sieht also folgendermaßen aus:

>>>

>>> d = {'foo': 1, 'bar': 2, 'baz': 3}
>>> for k, v in d.items():
...     print('k =', k, ', v =', v)
...
k = foo , v = 1
k = bar , v = 2
k = baz , v = 3

Dierange() Funktion

Im ersten Abschnitt dieses Tutorials haben Sie eine Artfor-Schleife namensnumeric range loop gesehen, in der numerische Start- und Endwerte angegeben werden. Obwohl diese Form derfor-Schleife nicht direkt in Python integriert ist, ist sie leicht zu finden.

Wenn Sie beispielsweise die Werte von0 bis4 durchlaufen möchten, können Sie dies einfach tun:

>>>

>>> for n in (0, 1, 2, 3, 4):
...     print(n)
...
0
1
2
3
4

Diese Lösung ist nicht schlecht, wenn es nur wenige Zahlen gibt. Aber wenn der Nummernkreis viel größer wäre, würde es ziemlich schnell langweilig werden.

Glücklicherweise bietet Python eine bessere Option - die integrierterange()-Funktion, die eine Iterable zurückgibt, die eine Folge von Ganzzahlen ergibt.

range(<end>) gibt eine Iterable zurück, die ganze Zahlen ergibt, die mit0 beginnen, bis<end>, jedoch nicht enthalten:

>>>

>>> x = range(5)
>>> x
range(0, 5)
>>> type(x)

Beachten Sie, dassrange() ein Objekt der Klasserange zurückgibt, keine Liste oder ein Tupel der Werte. Da einrange-Objekt iterierbar ist, können Sie die Werte erhalten, indem Sie sie mit einerfor-Schleife durchlaufen:

>>>

>>> for n in x:
...     print(n)
...
0
1
2
3
4

Sie können auch alle Werte mitlist() odertuple() auf einmal erfassen. In einer REPL-Sitzung kann dies eine bequeme Möglichkeit sein, schnell die Werte anzuzeigen:

>>>

>>> list(x)
[0, 1, 2, 3, 4]

>>> tuple(x)
(0, 1, 2, 3, 4)

Wenn jedochrange() in Code verwendet wird, der Teil einer größeren Anwendung ist, wird es normalerweise als schlechte Praxis angesehen,list() odertuple() auf diese Weise zu verwenden. Wie Iteratoren sindrange Objekte faul - die Werte im angegebenen Bereich werden erst generiert, wenn sie angefordert werden. Wenn Sielist() odertuple() für einrange-Objekt verwenden, werden alle Werte auf einmal zurückgegeben. Dies ist selten erforderlich, und wenn die Liste lang ist, kann dies Zeit und Speicher verschwenden.

range(<begin>, <end>, <stride>) gibt eine Iterable zurück, die Ganzzahlen ergibt, die mit<begin> beginnen, bis<end>, jedoch nicht enthalten. Wenn angegeben, gibt<stride> einen Betrag an, der zwischen den Werten übersprungen werden soll (analog zu dem Schrittwert, der für das Schneiden von Zeichenfolgen und Listen verwendet wird):

>>>

>>> list(range(5, 20, 3))
[5, 8, 11, 14, 17]

Wenn<stride> weggelassen wird, wird standardmäßig1 verwendet:

>>>

>>> list(range(5, 10, 1))
[5, 6, 7, 8, 9]
>>> list(range(5, 10))
[5, 6, 7, 8, 9]

Alle fürrange() angegebenen Parameter müssen Ganzzahlen sein, aber jeder von ihnen kann negativ sein. Wenn<begin> größer als<end> ist, muss<stride> natürlich negativ sein (wenn Sie Ergebnisse wünschen):

>>>

>>> list(range(-5, 5))
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]

>>> list(range(5, -5))
[]
>>> list(range(5, -5, -1))
[5, 4, 3, 2, 1, 0, -1, -2, -3, -4]

Technical Note: Genau genommen istrange() nicht genau eine integrierte Funktion. Es wird als aufrufbare Klasse implementiert, die einen unveränderlichen Sequenztyp erstellt. Aus praktischen Gründen verhält es sich jedoch wie eine integrierte Funktion.

Weitere Informationen zurange() finden Sie im Real Python-ArtikelPython’s range() Function (Guide).

Ändern des Schleifenverhaltens vonfor

Sie haben im vorherigen Tutorial in dieser Einführungsserie gesehen, wie die Ausführung einerwhile-Schleife mitbreak and continue statements unterbrochen und mitelse clause geändert werden kann. Diese Funktionen sind auch für diefor-Schleife verfügbar.

Die Anweisungenbreak undcontinue

break undcontinue funktionieren mitfor-Schleifen genauso wie mitwhile-Schleifen. break beendet die Schleife vollständig und fährt mit der ersten Anweisung fort, die der Schleife folgt:

>>>

>>> for i in ['foo', 'bar', 'baz', 'qux']:
...     if 'b' in i:
...         break
...     print(i)
...
foo

continue beendet die aktuelle Iteration und fährt mit der nächsten Iteration fort:

>>>

>>> for i in ['foo', 'bar', 'baz', 'qux']:
...     if 'b' in i:
...         continue
...     print(i)
...
foo
qux

Dieelse-Klausel

Einefor-Schleife kann auch eineelse-Klausel enthalten. Die Interpretation ist analog zu der einerwhile-Schleife. Dieelse-Klausel wird ausgeführt, wenn die Schleife durch Erschöpfung des iterablen beendet wird:

>>>

>>> for i in ['foo', 'bar', 'baz', 'qux']:
...     print(i)
... else:
...     print('Done.')  # Will execute
...
foo
bar
baz
qux
Done.

Dieelse-Klausel wird nicht ausgeführt, wenn die Liste mit einerbreak-Anweisung unterbrochen wird:

>>>

>>> for i in ['foo', 'bar', 'baz', 'qux']:
...     if i == 'bar':
...         break
...     print(i)
... else:
...     print('Done.')  # Will not execute
...
foo

Fazit

In diesem Tutorial wurde diefor-Schleife vorgestellt, das Arbeitspferd vondefinite iteration in Python.

Sie haben auch das Innenleben voniterables unditerators kennengelernt, zwei wichtigen Objekttypen, die einer bestimmten Iteration zugrunde liegen, aber auch in einer Vielzahl anderer Python-Codes eine herausragende Rolle spielen.

In den nächsten beiden Tutorials dieser Einführungsserie werden Sie ein wenig schalten und untersuchen, wie Python-Programme überinput von der Tastatur undoutput zur Konsole mit dem Benutzer interagieren können.