For-Schleifen


Einführung

Wie auch die while-Schleife ist die for-Schleife eine Kontrollstruktur, mit der eine Gruppe von Anweisungen (ein Block) wiederholt ausführt werden kann.
Die Syntax der For-Schleifen unterscheiden sich in den verschiedenen Programmiersprachen. Ebenso ist die Semantik einer For-Schleife, also wie sie vom Compiler oder Interpreter zu verstehen bzw. auszuführen ist, von Programmiersprache zu Programmiersprache unterschiedlich.
Die "klassische" numerische Schleife, wie sie C und C++ kennt, besitzt eine Schleifenvariable, die mit einem Startwert initialisiert wird und nach jedem Durchlauf des Schleifenkörpers verändert wird, d.h. meistens um einen bestimmten Wert (z.B. 1) erhöht oder vermindert wird, bis der definierte Zielwert erreicht ist. Man nennt diese Schleifenform auch Zählschleife, weil die Schleifenvariable und damit auch der Startwert, der Endwert und die Schrittweite numerisch sein müssen.
Im Beispiel sehen wir eine for-Schleife in C, die die Zahlen von eins bis 100 ausdruckt:
for( i = 0; i < 100; i++)
   printf("i: %d\n", i);
Auch wenn Sie diese Schleifenform bereits in C oder einer anderen Sprache liebgewonnen haben, müssen wir Sie leider enttäsuchen: Python kennt keine solche for-Schleife. Wohlgemerkt "keine solche" aber sehr wohl eine for-Schleife. Die in Python benutzte Art von For-Schleife entspricht der in der Bash-Shell oder in Perl verwendeten foreach-Schleife. Bei dieser Schleifenart handelt es sich um ein Sprachkonstrukt mit dessen Hilfe nacheinander die Elemente einer Menge oder Liste bearbeitet werden können. Dazu werden sie einer Variable zugewiesen.

Syntax der For-Schleife in Python

Im folgenden sehen wir die allgemeine Syntax der for-Schleife in Python. Sequenz steht für ein iterierbares Objekt.
Ring als Symbol der for-Schleife

for Variable in Sequenz:
	Anweisung_1
	Anweisung_2
	...
	Anweisung_n
else:
	Else-Anweisung_1
	Else-Anweisung_2
	...
	Else-Anweisung_m
Wie bereits gesagt, dient in Python die For-Schleife zur Iteration über ein Sequenz von Objekten, während sie in vielen anderen Sprachen meist nur "eine etwas andere while-Schleife" ist.

Beispiel einer for-Schleife in Python:
>>> languages = ["C", "C++", "Perl", "Python"] 
>>> for language in languages:
...     print(language)
... 
C
C++
Perl
Python
>>> 
Can of Spam Der optionale else-Block ist etwas Besonderes in Python. Während Perl-Programmierer dieses Konstrukt vertraut ist, ist es für C und C++-Programmierer ein ungewöhnliches Konzept. Semantisch funktioniert der optionale else-Block der for-Anweisung wie der else-Block der while-Anweisung. Er wird nur ausgeführt, wenn die Schleife nicht durch eine break-Anweisung abgebrochen wurde. Das bedeutet, dass der else-Block nur dann ausgeführt wird, wenn alle Elemente der Sequenz abgearbeitet worden sind.

Trifft der Programmablauf auf eine break-Anweisung, so wird die Schleife sofort verlassen und das Programm wird der Anweisung fortgesetzt, die der for-Schleife folgt, falls es überhaupt noch Anweisungen nach der for-Schleife gibt.

Überlicherweise befindet sich die break-Anweisung innerhalb einer Konditionalanweisung, wie im folgenden Beispiel:
edibles = ["ham", "spam","eggs","nuts"]
for food in edibles:
    if food == "spam":
        print("No more spam please!")
        break
    print("Great, delicious " + food)
else:
    print("I am so glad: No spam!")
print("Finally, I finished stuffing myself")
Wenn wir obiges Beispiel unter for.py speichern und aufrufen, erhalten wir folgende Ausgaben:
$ python for.py 
Great, delicious ham
No more spam please!
Finally, I finished stuffing myself
$ 
Wenn wir "spam" aus der Liste der essbaren Dinge entfernen, erhalten wir folgende Ausgabe:
$ python for.py 
Great, delicious ham
Great, delicious eggs
Great, delicious nuts
I am so glad: No spam!
Finally, I finished stuffing myself
$
Vielleicht ist unsere Abscheu vor dem Dosenfutter "spam" nicht so groß, dass wir sofort aufhören zu essen. In diesem Fall kommt die continue-Anweisung ins Spiel. In dem folgenden kleinen Skript benutzen wir continue, um mit dem nächsten Artikel der essbaren Artikel weiterzumachen. "continue" schützt uns davor, "spam" essen zu müssen:
edibles = ["ham", "spam", "eggs","nuts"]
for food in edibles:
    if food == "spam":
        print("No more spam please!")
        continue
    print("Great, delicious " + food)
    # here can be the code for enjoying our food :-)
else:
    print("I am so glad: No spam!")
print("Finally, I finished stuffing myself")
Die Ausgabe sieht dann wie folgt aus:
$ python for.py 
Great, delicious ham
No more spam please!
Great, delicious eggs
Great, delicious nuts
I am so glad: No spam!
Finally, I finished stuffing myself
$


Die range()-Funktion

In Python gibt es eine einfache Möglichkeiten Zählschleifen zu simulieren. Dazu benötigt man die range()-Funktion. range() liefert einen Iterator, der Zahlen in einem bestimmten Bereich (range) bei Bedarf, - also beispielsweise in einer For-Schleife, - liefern kann.
Bevor wie die allgemeine Syntax angeben, zeigen wir die einfachste Benutzung von range() in einem Beispiel:

>>> range(10)
range(0, 10)
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> 
Obiges Beispiel zeigt, dass range(), wenn man es mit einem einzelnen Argument aufgeruft, einen Iterator liefert, der die Zahlen von 0 (inklusive) bis zu diesem Wert (exklusive) generieren kann. Um eine entsprechende Liste aus dem Iterator zu erzeugen, benutzt man den cast-Operator list().
range() kann aber auch mit zwei Argumenten aufgerufen werden:
range(begin,end)
Dann wird ein Iterator für alle ganzen Zahlen von begin (einschließlich) bis end (aussschließlich) geliefert.
Beispiel:
>>> range(4,10)
range(4, 10)
>>> list(range(4,10))
[4, 5, 6, 7, 8, 9]
>>> 

Mit einem optionalen dritten Argument kann man range() noch die Schrittweite mitgeben, wie wir im folgenden Beispiel sehen:
>>> list(range(4,50,5))
[4, 9, 14, 19, 24, 29, 34, 39, 44, 49]
>>> 
Das ganze geht natürlich auch rückwärts:
>>> list(range(42,-12,-7))
[42, 35, 28, 21, 14, 7, 0, -7]
>>> 
Besonders sinnvoll wird die range()-Funktion im Zusammenspiel mit der for-Schleife. Im nachfolgenden Beispiel bilden wir die Summe der Zahlen von 1 bis 100:
n = 100

sum = 0
for counter in range(1,n+1):
    sum = sum + counter

print("Sum of 1 until " + str(n) + ": " + str(sum) )

Beispiel: Berechnung der pythagoräischen Zahlen

Beweis des Satzes von Pythagoras Die meisten glauben, dass der Satz von Pythagoras von Pythagoras entdeckt worden war. Warum sonst sollte der Satz seinen Namen erhalten haben. Aber es gibt eine Debatte, ob dieser Satz nicht auch unabhängig von Pyhtagoras und vor allen Dingen bereits früher entdeckt worden sein könnte. Für die Pythagoräer - eine mystische Bewegung, die sich auf die Mathematik, Religion und die Philosophie begründete - waren die ganzen Zahlen, die den Satz des Pythagoras erfüllten besondere Zahlen, die für sie heilig waren.

Heutzutage haben die Pythagoräischen Zahlen nichts mystisches mehr. Obwohl sie für manche Schülerin oder Schüler oder ander Personen, die mit der Mathematik auf Kriegsfuß stehen, immer noch so erscheinen mögen.

Ganz unromantisch gilt in der Mathematik:
Drei natürliche Zahlen, welche die Gleichung

a2+b2=c2

erfüllen, heißen pythagoräische Zahlen.

Das folgende Programm berechnet alle pythagoräischen Zahlen bis zu einer einzugebenden maximalen Zahl:
#!/usr/bin/env python3
from math import sqrt
n = int(input("Maximale Zahl? "))
for a in range(1,n+1):
    for b in range(a,n):
        c_square = a**2 + b**2
        c = int(sqrt(c_square))
        if ((c_square - c**2) == 0):
            print(a, b, c)

Iteration über eine Liste mit range()

Falls man auf die Indexe einer Liste zugreifen möchte, scheint es keine gute Idee zu sein eine For-Schleife zur Iteration über die Liste zu nutzen. Man kann dann zwar alle Elemente erreichen, aber der Index eines Elementes ist nicht verfügbar. Aber es gibt eine Möglichkeit sowohl auf den Index als auch auf das Element zugreifen zu können. Die Lösung besteht darin range() in Kombination mit der len()-Funktion, die einem die Anzahl der Listenelemente liefert, zu benutzen:
fibonacci = [0,1,1,2,3,5,8,13,21]
for i in range(len(fibonacci)):
    print(i,fibonacci[i])
print()
Die Ausgabe sieht wie folgt aus:
0 0
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21

Listen-Iteration mit Seiteneffekten

Falls man über eine Liste iteriert, sollte man vermeiden die Liste im Schleifenkörper (body) zu verändern. Was passieren kann, zeigen wir im folgenden Beispiel:
colours = ["red"]
for i in colours:
    if i == "red":
        colours += ["black"]
    if i == "black":
        colours += ["white"]
print(colours)
Was wird durch die Anweisung "print(colours)" ausgegeben?
['red', 'black', 'white']
Am besten benutzt man eine Kopie der Liste, wie im nächsten Beispiel:
colours = ["red"]
for i in colours[:]:
    if i == "red":
        colours += ["black"]
    if i == "black":
        colours += ["white"]
print(colours)
Die Ausgabe sieht nun wie folgt aus:
['red', 'black']
Auch jetzt haben wir die Liste verändert, aber "bewusst" innerhalb des Schleifenkörpers. Aber der Elemente, die über die For-Schleife iteriert werden, bleiben unverändert durch die Iterationen.