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 1 bis 100 ausdruckt:

for( i = 1; 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äuschen: 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, also beispielsweise eine Liste, ein Tupel oder ein Dictionary.

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-Programmierern 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 mit der Anweisung fortgesetzt, die der for-Schleife folgt, falls es überhaupt noch Anweisungen nach der for-Schleife gibt.

Üblicherweise 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")
Great, delicious ham
No more spam please!
Finally, I finished stuffing myself
edibles = ["ham","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")
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"]
spam = False
for food in edibles:
    if food == "spam":
        print("No more spam please!")
        spam = True
        continue
    print("Great, delicious " + food)
    # here can be the code for enjoying our food :-)
else:
    if spam:
        print("I didn't like the spam!")
    else:
        print("I am so glad: No spam!")
print("Finally, I finished stuffing myself")
Great, delicious ham
No more spam please!
Great, delicious eggs
Great, delicious nuts
I didn't like the spam!
Finally, I finished stuffing myself

Die range()-Funktion

In Python gibt es eine einfache Möglichkeit 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)
Ausgabe: :

range(0, 10)
list(range(10))
Ausgabe: :

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Obiges Beispiel zeigt, dass range(), wenn man es mit einem einzelnen Argument aufruft, 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 (ausschließlich) geliefert. Beispiel:

range(4, 10)
Ausgabe: :

range(4, 10)
list(range(4, 10))
Ausgabe: :

[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))
Ausgabe: :

[4, 9, 14, 19, 24, 29, 34, 39, 44, 49]

Das ganze geht natürlich auch rückwärts:

list(range(42, -12, -7))
Ausgabe: :

[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
s = 0
for counter in range(1, n+1):
    s += counter
print("Sum of 1 until " + str(n) + ": " + str(s) )
Sum of 1 until 100: 5050

Dies lässt sich nun ganz einfach im Zusammenspiel mit range und der eingebauten Funktion "sum" bewerkstelligen. Mit "sum" kann man die Elemente numerischer Listen oder Tupel addieren, d.h. Listen oder Tupel, die nur numerische Werte enthalten. die Summe der Zahlen von 1 bis n lässt sich also ganz einfach wie folgt berechnen:

sum(range(101))
Ausgabe: :

5050

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 Pythagoras 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 andere 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:

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)
Maximale Zahl? 10
3 4 5
6 8 10

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()
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)
['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)
['red', 'black']

Auch jetzt haben wir die Liste verändert, aber "bewusst" innerhalb des Schleifenkörpers. Aber die Elemente, die über die For-Schleife iteriert werden, bleiben unverändert durch die Iterationen.