For-Schleifen

Einführung

Thinking of a for loop

Wie auch die while-Schleife ist die for-Schleife eine Kontrollstruktur, mit der eine Gruppe von Anweisungen (ein Block) wiederholt ausführt werden kann.

Eine for-Schleife in Python wird für die Iteration über eine Sequenz (wie eine Liste, ein Tupel, eine Zeichenkette oder einen Bereich) oder andere iterierbare Objekte verwendet. Sie ist eine grundlegende Kontrollstruktur in der Programmierung, die es Ihnen ermöglicht, einen Codeblock eine bestimmte Anzahl von Malen zu wiederholen oder durch die Elemente einer Sequenz zu iterieren.

Was ist also mit der while-Schleife? Brauchen wir eine andere Art von Schleife in Python? Können wir nicht alles mit der while-Schleife machen? Ja, wir können "for"-Schleifen in "while"-Schleifen umschreiben. Aber bevor wir weitermachen, möchten Sie zumindest ein Beispiel für eine for-Schleife sehen.

Syntax einer for-Schleife

As we mentioned earlier, the Python for loop is an iterator based for loop. It steps through the items of lists, tuples, strings, the keys of dictionaries and other iterables. The Python for loop starts with the keyword "for" followed by an arbitrary variable name, which will hold the values of the following sequence object, which is stepped through. The general syntax looks like this:

for <variable> in <sequence>:
    <statements>
else:
    <statements>

A first example of a for loop:

In [2]:
performance_levels = ("Python für Programmieranfänger", 
                      "Python für Programmiererfahrene", 
                      "Python für Fortgeschrittene")

# Iterate through each level in the tuple
for level in performance_levels:
    # Print the current level
    print(level)
Python für Programmieranfänger
Python für Programmiererfahrene
Python für Fortgeschrittene

Allgemeines über for-Schleifen

Dieses Unterkapitel kann von Anfängerinnen und Anfängern getrost übersprungen werden, da es hier vor allen Dingen um allgemeine Unterschiede von for-Schleifen in verschiedenen Programmiersprachen geht.

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:

In [17]:
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:

In [1]:
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
In [2]:
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:

In [2]:
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:

In [4]:
range(10)
Out[4]:
range(0, 10)
In [5]:
list(range(10))
Out[5]:
[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:

In [6]:
range(4, 10)
Out[6]:
range(4, 10)
In [7]:
list(range(4, 10))
Out[7]:
[4, 5, 6, 7, 8, 9]

Mit einem optionalen dritten Argument kann man range() noch die Schrittweite mitgeben, wie wir im folgenden Beispiel sehen:

In [8]:
list(range(4, 50, 5))
Out[8]:
[4, 9, 14, 19, 24, 29, 34, 39, 44, 49]

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

In [9]:
list(range(42, -12, -7))
Out[9]:
[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:

In [10]:
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:

In [11]:
sum(range(101))
Out[11]:
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:

In [12]:
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:

In [13]:
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:

In [14]:
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:

In [16]:
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.

Übungen mit for-Schleifen

Übung 1: Fibonacci-Zahlen

Erzeugen und drucken Sie die ersten n Zahlen der Fibonacci-Folge mit Hilfe einer for-Schleife.

Übung 2: Rautenmuster

Erstellen Sie ein Programm, das ein Rautenmuster mit Sternchen (*) ausgibt, wie im folgenden Beispiel:

    *
   ***
  *****
 *******
*********
 *******
  *****
   ***
    *

Übung 3: Primzahlen

Schreiben Sie ein Programm, das mit Hilfe einer for-Schleife alle Primzahlen zwischen 1 und 50 findet und ausgibt.

Übung 4: Fizz, Buzz, FizzBuzz

Bei der nächsten Aufgabe geht es um ein Kinderspiel. "Fizz buzz" ist ein Gruppen-Wortspiel für Kinder, das ihnen etwas über die mathematische Division beibringen soll. Die spielenden Kinder zählen abwechselnd inkremental, wobei jede durch drei teilbare Zahl durch das Wort „Fizz“ und jede durch fünf teilbare Zahl durch das Wort „Buzz“ ersetzt wird.

Schreibe ein Programm welches die Zahlen von 1 bis 42 ausgibt, aber entsprechend des Kinderspieles für Vielfache von 3 "Fizz" und für Vielfache von 5 "Buzz" ausgibt Für Zahlen, die Vielfache von sowohl 3 als auch 5 sind, wird "FizzBuzz" gedruckt.

Übung 5: Ramanujan-Hardy-Zahl

In dieser Übung geht es um die Ramanujan-Hardy-Zahl. Es gibt eine kleine Anekdote des Mathematikers G.H. Hardy, als er den indischen Mathematiker Srinivasa Ramanujan im Krankenhaus besuchte. Sie lautet wie folgt:

Ich erinnere mich, dass ich ihn einmal besuchte, als er krank in Putney lag. Ich war im Taxi mit der Nummer 1729 mitgefahren und bemerkte, dass mir die Nummer ziemlich langweilig vorkam und ich hoffte, dass dies kein schlechtes Omen sei. "Nein", antwortete er, "es ist eine sehr interessante Zahl; sie ist die kleinste Zahl, die sich als Summe zweier Quadrate auf zwei verschiedene Arten ausdrücken lässt."

Aus diesem Grund ist 1732 auch als Ramanujan-Hardy-Zahl bekannt.

Können Sie dies mit einem Python-Programm überprüfen?

Aufgabe 6:

1729 ist die kleinste Zahl, die durch eine Loeschsche quadratische Form $a^2 + ab + b^2$ auf vier verschiedene Arten dargestellt werden kann, mit positiven ganzen Zahlen a und b .

Finde diese Zahl mit einem Python-Programm.

Aufgabe 7: Pascalsche Dreiecksbeziehung

Schreibe ein Python-Programm, das die ersten n Zeilen des Pascalschen Dreiecks erzeugt und ausgibt. Das Pascalsche Dreieck ist ein mathematisches Zahlenmuster, bei dem jede Zahl die Summe der beiden Zahlen direkt über ihr ist. Die ersten Zeilen des Pascalschen Dreiecks sehen wie folgt aus:

          1               
         1 1              
        1 2 1             
       1 3 3 1            
      1 4 6 4 1                

Dein Programm soll eine ganze Zahl n als Eingabe annehmen und die ersten n Zeilen des Pascalschen Dreiecks ausgeben.Man muss verschachtelte for-Schleifen verwenden, um jede Zeile zu berechnen und zu drucken.

Diese Übung kann recht anspruchsvoll sein, aber sie ist eine gute Möglichkeit, verschachtelte Schleifen und die Erzeugung von Mustern in Python zu üben.

Lösungen

Lösung zur Übung 1

In [1]:
n = int(input("Anzahl der zu erzeugenden Fibonacci-Zahlen: "))

# Die beiden ersten Fibonacci-Zahlen
fibonacci_sequence = [0, 1]

for i in range(2, n):
    next_number = fibonacci_sequence[-1] + fibonacci_sequence[-2]
    fibonacci_sequence.append(next_number)

# Ausgabe der ersten n Fibonacci Zahlen
print("Fibonacci Sequence:")
for number in fibonacci_sequence[:n]:
    print(number, end=" ")
Fibonacci Sequence:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 

Lösung zur Übung 2

In [2]:
height = int(input("Höhe der zu erzeugenden Raute: "))

height_is_even = height % 2 == 0
middle = height // 2 if height_is_even else height // 2 + 1
    
# Erzeugen der ersten Hälfte der Raute:
spaces = "*"
for counter in range(0, middle):
    print(spaces.center(middle*2+1))
    spaces += "**"
# zweite Hälfte der Raute:
spaces = spaces[:-2]
if height_is_even:
    # letzte Zeile muss verdoppelt werden:
    print(spaces.center(middle*2+1))
while len(spaces) > 1:
    spaces = spaces[:-2]
    print(spaces.center(middle*2+1))
      *      
     ***     
    *****    
   *******   
  *********  
 *********** 
  *********  
   *******   
    *****    
     ***     
      *      

Lösung zur Aufgabe 3

In [3]:
print("Primzahlen zwischen 1 und 50:")
for number in range(1, 51):
    if number <= 1:
        is_prime = False
    elif number <= 3:
        is_prime = True
    elif number % 2 == 0 or number % 3 == 0:
        is_prime = False
    else:
        is_prime = True
        i = 5
        while i * i <= number:
            if number % i == 0 or number % (i + 2) == 0:
                is_prime = False
                break
            i += 6
    if is_prime:
        print(number, end=" ")
Primzahlen zwischen 1 und 50:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 

Lösung zur Aufgabe 4

In [4]:
for number in range(1, 43):
    # Prüfe, ob die Uahl ein Vielfaches von 3 und 5 ist:
    if number % 3 == 0 and number % 5 == 0:
        print("FizzBuzz")
    # Prüfe, ob die Zahl ein Vielfaches von 3 ist
    elif number % 3 == 0:
        print("Fizz")
    # Prüfe, ob die Zahl ein Vielfaches von 5 ist
    elif number % 5 == 0:
        print("Buzz")
    else:
        print(number)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
31
32
Fizz
34
Buzz
Fizz
37
38
Fizz
Buzz
41
Fizz

Lösung zur Aufgabe 5

In [5]:
import math

number = 1729
n = int(number ** (1/3))

cubes = {}
for i in range(n+1):
    for j in range(i):
        result = i ** 3 + j ** 3
        if result in cubes:
            cubes[result].append((i, j))
        else:
            cubes[result] = [(i,j)]
        if result > number:
            break

for x in cubes:
    if len(cubes[x]) > 1:
        print(x, cubes[x])
1729 [(10, 9), (12, 1)]

Lösung zur Aufgabe 6

In [6]:
import math

number = 1729
n = int(number ** (1/2))

results = {}
for a in range(n+1):
    for b in range(a):
        result = a**2 + a*b + b**2
        if result in results:
            results[result].append((a, b))
        else:
            results[result] = [(a,b)]
        if result > number:
            break

for x in results:
    if len(results[x]) > 3:
        print(x, results[x])
1729 [(25, 23), (32, 15), (37, 8), (40, 3)]

Lösung zur Aufgabe 7

In [17]:
n = int(input("Zeilenanzahl Pascal'sches Dreieck: "))

triangle = []
# Erzeugung des Pascal'schen Dreiecks
for i in range(n):
    row = []
    for j in range(i + 1):
        if j == 0 or j == i:
            # rstes und letztes Element einer Reihe sind 1
            row.append(1)
        else:
            previous_row = triangle[i - 1]
            row.append(previous_row[j - 1] + previous_row[j])
    triangle.append(row)

# Ausgabe Pascal'sches Dreieck
for row in triangle:
    print(" ".join(map(str, row)).center(n * 3))
             1             
            1 1            
           1 2 1           
          1 3 3 1          
         1 4 6 4 1         
       1 5 10 10 5 1       
      1 6 15 20 15 6 1     
    1 7 21 35 35 21 7 1    
   1 8 28 56 70 56 28 8 1  
In [ ]: