Kontrollstrukturen
Einfache Programme bestehen aus der reinen Aneinanderreihung von Anweisungen. Mit Kontrollstrukturen kann die Ausführung von Anweisungen gesteuert werden, sodass beliebige Wiederholungen von Quellcodeblöcken (aka Schleifen
, Loops
) oder Verzweigungen (aka Bedingte Anweisung
, If/Else Block
) im Programmablauf realisiert werden können. Erst durch die Nutzung von Kontrollstrukturen lassen sich komplexere Algorithmen realisieren.
Programmablaufpläne
Programmablaufpläne (PAP) sind ein nützliches Hilfsmittel um Algorithmen oder Abläufe zu visualisieren und zu dokumentieren. Für Programmieranfänger:innen eignen sie sich um ein besseres Verständnis für Kontrollstrukturen in Programmiersprachen zu erlangen. Programme können mit unterschiedlichen Symbolen, welche jeweils eine entsprechende Bedeutung haben, grafisch beschrieben werden. Die Symbole für Programmablaufpläne sind sogar nach der DIN 66001 genormt. In der folgenden Tabelle finden sich die wesentlichen Symbole:
Symbol | Bezeichnung | Beschreibung |
---|---|---|
![]() |
Eingabe, Ausgabe | Mit dem Parallelogramm wird eine externe Eingabe oder eine Ausgabe des Programms dargestellt. Für ein Kommandozeilenprogramm würden die Python Funktionen input bzw. print mit diesem Symbol dargestellt werden. |
![]() |
Anweisung | Jede Aufgabe (zB Berechnung) die im Programm ausgeführt werden soll, wird über ein Rechteck dargestellt. |
![]() |
Verzweigung | Mit der Raute wird eine Ja/Nein Entscheidung abgebildet. Der weitere Programmfluss folgt nur einem der ausgehenden Verbindungen. |
![]() |
Start/Stop | Mit einem Oval oder Rechteck mit gerundeten Ecken wird ein Start- oder Stoppunkt des Programms definiert. Jedes Programm hat genau einen Startpunkt. Ein Programm hat mindestens einen Stoppunkt. |
![]() |
Verbindung | Mit Pfeilen wird eine Verbindung zwischen den einzelnen Elementen im PAP erzeugt. Die Verbindung spiegelt dabei den Programmablauf wieder. |
PAP Beispiel: Fakultätsberechnung
Im folgenden Beispiel soll ein PAP für die Berechnung der mathematischen Fakultät erstellt werden. Das Programm soll auch über Ein- und Ausgabemöglichkeiten verfügen. Die mathematische Fakultät n!
ist eine Funktion die einer natürlichen Zahl das Produkt aller natürlichen Zahlen (ohne Null) kleiner und gleich dieser Zahl zuordnet. Als Beispiel wäre die Fakultät der Zahl 5
also 5!
über die Multiplikation 5 * 4 * 3 * 2 * 1
zu errechnen (5! = 120
).
PAP Beispiel: Größter gemeinsamer Teiler
Im folgenden Beispiel soll ein PAP für die Berechnung des größten gemeinsamen Teilers zweier natürlicher Zahlen erstellt werden. Das Programm soll auch über Ein- und Ausgabemöglichkeiten verfügen.
Als Algorithmus soll der euklidische Algorithmus zum Einsatz kommen. Der euklidische Algorithmus ist ein Algorithmus aus dem mathematischen Teilgebiet der Zahlentheorie. Das Verfahren ist nach dem griechischen Mathematiker Euklid benannt, der es in seinem Werk „Die Elemente“ beschrieben hat.
Der Algorithmus kann mit Strecken erklärt werden. Am Beispiel der Zahl 15
und 9
. Man stelle sich vor es gibt die Strecke A
und die Strecke B
, die eine Länge von 15
bzw. 9
haben:
A |---------------|
B |---------|
Der Algorithmus geht nun iterativ so vor, dass immer die kürzere Strecke von der längeren Strecke abgezogen wird, solange bis beide Strecken gleich lang sind. Wenn die Strecken nach mehreren Substraktionen die gleiche Länge aufweisen, hat man den größten gemeinsamen Teiler errechnet. Für das Beispiel 15
und 9
würde dies folgendermaßen aussehen:
Start:
|---------------|
|---------|
1. Substraktion:
|---------|
|------|
2. Substraktion:
|------|
|---|
3. Substraktion:
|---|
|---|
Nach 3 Substraktionen würden also beide Strecken gleich lang sein und der größte gemeinsame Teiler der Zahlen 15
und 9
würde mit 3
feststehen. Als Programmablaufplan würde der Algorithmus folgendermaßen repräsentiert werden können:
Bedingte Anweisungen
Mit einer bedingten Anweisung kann der Programmablauf gesteuert werden. Dies wurde im PAP mit der Raute
realisiert. Es wird also eine Bedingung definiert. Jenachdem ob die Bedingung wahr
oder falsch
ist, wird dem einen oder der anderen Zweig im Programmablauf gefolgt. In Python wird der sog. If/Else Block
für Verzweigungen verwendet. Für die Formulierung von Bedingungen können Vergleichsoperationen oder logische Operationen verwendet werden.
Im folgenden Beispiel soll geprüft werden ob eine Zahl größer 10
ist oder nicht. Falls die Zahl größer 10
ist, soll der String "Die Zahl ist größer 10"
ausgegben werden. Anderenfalls soll der String "Die Zahl ist nicht größer 10"
ausgegeben werden:
number = int(input("Gib eine Zahl ein:"))
if number > 10:
print("Die Zahl ist größer 10")
else:
print("Die Zahl ist nicht größer 10")
Im Beispiel werden die Schlüsselwörter if
und else
für die Formulierung der bedingten Anweisung verwendet. Wichtig ist, dass nach dem Schlüsselwort if
immer eine Bedingung stehen muss und auf die Bedingung immer der Doppelpunkt :
folgt. Die Bedingung kann dabei beliebig komplex definiert sein, so könnten Vergleichsoperationen mit logischen Operationen beliebig verknüpft werden.
Falls die Bedingung wahr
ist, würde der eingerückte Quellcodeabschnitt nach der if
Zeile ausgeführt. Falls die Bedingung falsch
ist, würde der eingerückte Quellcodeabschnitt nach der else
Zeile ausgeführt. Da ein Wahrheitswert nur wahr
oder falsch
sein kann, muss für die else
Zeile keine eigene Bedingung formuliert werden. Der else
Abschnitt würde also immer dann ausgeführt werden, wenn die Bedingung der if
Zeile falsch
ist.
Eine bedingte Anweisung muss nicht zwingend einen else
Zweig aufweisen. Wenn es nicht notwendig ist etwas auszuführen, wenn die Bedingung des if
Zweiges falsch
ist, kann der else
Zweig ausgespart werden:
number = int(input("Gib eine Zahl ein:"))
if number > 10:
print("Die Zahl ist größer 10")
print("Danke und auf Wiedersehen")
Mehrere Verzweigungen
Eine Verzweigung kann auch mehr als zwei Ausführungspfade erzeugen. Mit dem Schlüsselwort elif
können alternative Bedingungen angegeben werden. Wichtig ist, dass die Bedingungen sequentiell von oben nach unten geprüft werden.
Die erste Bedingung die als wahr
ausgewertet wird, bestimmt den Verlauf des Programms. Würden weitere Bedingungen ebenfalls als wahr
ausgewertet werden, würden diese ignoriert werden.
Im folgenden Programm wird ein ersten einfaches Spiel entwickelt. Im Spiel soll die Geheimzahl geraten werden. Jenachdem ob die eingegebene Zahl kleiner, größer oder gleich der Geheimzahl ist, sollen unterschiedliche Ausgaben getätigt werden:
secret = 42
guess = int(input('Rate die Zahl:'))
if guess == secret:
print('Sehr gut! Du hast die Zahl erraten')
elif guess < secret:
print('Leider, die Geheimzahl ist größer als deine Eingabe')
else:
print('Leider, die Geheimzahl ist kleiner als deine Eingabe')
Verzweigungen können grundsätzlich verschachtelt werden. Dies kann in manchen Fällen sinnvoll sein. Tiefe Verschachtelungen können auch die Lesbarkeit negativ beeinflussen, deshalb sollten Verschachtelungen sehr bedacht eingesetzt werden. Im folgenden Beispiel wird exemplarisch gezeigt, wie eine Verschachtelung für das Raten der Geheimzahl eingesetzt werden könnte:
secret = 42
guess = int(input('Rate die Zahl:'))
if guess == secret:
print('Sehr gut! Du hast die Zahl erraten')
else:
if guess < secret:
print('Leider, die Geheimzahl ist größer als deine Eingabe')
else:
print('Leider, die Geheimzahl ist kleiner als deine Eingabe')
Wiederholungen mit Schleifen
Mit einer Schleife kann ein Quellcodeabschnitt wiederholt ausgeführt werden. Die Wiederholung wird solange durchgeführt, solange die Schleifen-Bedingung als wahr
ausgewertet wird. In Python werden Schleifen u.a. mit dem Schlüsselwort while
realisert. Dabei gibt es den Schleifenkopf, welcher die Bedingung enthält und den eingerückten Schleifenkörper mit dem zu wiederholenden Quellcodeabschnitt.
Im folgenden Beispiel wird das bereits bekannte Ratespiel mittels einer Schleife realisiert. Die Bedingung der Schleife ist über guess != secret
definiert. Die Variable guess
wird dabei über die Benutzereingabe gesetzt. Dies bedeutet also, dass die Schleife solange wiederholt wird, bis die Benutzer:in die Zahl, welche in der Variable secret
gesetzt ist, errät.
secret = 42
guess = 0
while guess != secret:
guess = int(input("Rate die Zahl:"))
print("Super die Zahl wurde erraten!")
Neben der Bedingung im Schleifenkopf können für die Schleifensteuerung auch die beiden Schlüsselwörter continue
und break
herangezogen werden. Mit dem Schlüsselwort continue
wird ein Schleifendurchlauf übersprungen und mit dem Schlüsselwort break
wird die Schleife beendet.
Schleifenabbruch mit break
Neben der Bedingung im Schleifenkopf kann für die Schleifensteuerung auch das Schlüsselwort break
verwendet werden um die Schleife frühzeitig zu beenden. Für das Ratespiel könnte es definiert sein, dass das Spiel durch die Eingabe einer negativen Zahl beendet wird. Falls die Benutzer:in nach langem Suchen zu keiner Lösung gekommen ist, könnte durch die Angabe einer negativen Zahl das Programm beendet werden:
secret = 42
guess = 0
while guess != secret:
guess = int(input("Rate die Zahl:"))
if guess < 0:
break
print("Super die Zahl wurde erraten!")
Innerhalb der Schleife wird eine Bedingung angegeben, welche prüft ob die Variable guess
kleiner 0
ist. Falls dies der Fall ist, wird die Schleife mit dem Aufruf break
beendet.
Letzter Schleifendurchlauf
Das Programm aus dem letzten Abschnitt weist eine kosmetische Ungereimtheit auf. Wenn das Ratespiel durch die Eingabe einer negativen Zahl abgebrochen wird, wird trotzdem die Ausgabe "Super die Zahl wurde erraten!"
getätigt. Die Ausgabe sollte nur dann gemacht werden, wenn die Schleifenbedingung als falsch
ausgewertet wird. Über einen else
Zweig an der Schleife kann ein Anweisungsblock platziert werden, welcher nur ausgeführt wird, wenn die Schleifenbedingung als falsch
ausgewertet wird. Der else
Zweig an der Schleife wird nicht ausgeführt, wenn die Schleife über break
abgebrochen wird.
secret = 42
guess = 0
while guess != secret:
guess = int(input("Rate die Zahl:"))
if guess < 0:
break
else:
print("Super die Zahl wurde erraten!")
Schleifendurchlauf überspringen mit continue
Einzelne Schleifendurchläufe können mit dem Schlüsselwort continue
übersprungen werden. Im folgenden Beispiel sollen alle Zahlen von 1 bis 30 ausgegeben werden, welche nicht durch 3 teilbar sind:
n = 0
while n < 30:
n += 1
if n % 3 == 0:
continue
print("{} ist eine Zahl die nicht durch 3 teilbar ist.".format(n))
Verschachtelte Schleifen
Schleifen können grundsätzlich auch beliebig verschatelt werden. Wichtig dabei ist vorallem, dass man die Lesbarkeit des enstehenden Quellcodes nicht außer Acht lässt. Im folgenden Quellcode soll ein Spielfeld für das Spiel TicTacToe
erzeugt werden:
grid = ""
i = 0
while i < 3:
grid += "+---+---+---+\n"
i += 1
j = 0
while j < 3:
grid += "| "
j += 1
else:
grid += "|\n"
else:
grid += "+---+---+---+"
print(grid)
Die Ausgabe des obigen Quellcodes würde folgendes erzeugen:
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
For-Schleife
Die for
-Schleife nutzt das sog. Iterator Design Pattern um zusammengesetzte Datenstrukturen sequentiell zu iterieren. Eine Zeichenkette ist ein Beispiel für eine zusammengesetzte Datenstruktur. Die Zeichenkette 'abcd'
ist zusammengesetzt aus den 4 Elementen (Characters) 'a'
, 'b'
, 'c'
und 'd'
. Im folgenden Beispiel wird die for-Schleife genutzt um durch die Zeichenkette 'abcd'
zu iterieren. Die for-Schleife wird dabei über die Schlüsselwörter for
und in
realisiert.
for char in 'abcd':
print("Character: '{}'".format(char))
Python bietet die sehr nützliche built-in Funktion range
. Mit dieser Funktion können Zählerschleifen realisiert werden. Mit range
kann eine iterierbare Sequenz von Zahlen erzeugt werden, welche dann über die for-Schleife durchlaufen werden kann. Die range
Funktion hat folgende Funktionsaufrufe definiert:
range(end)
: von 0 bis end-1range(start, end)
:von start bis end-1range(start, end, step)
:von start bis end-1 in der Schrittweite step
Im folgenden Beispiel wird mit range
eine Zahlenfolgne von inklusive 10
bis exklusive 21
mit Schrittweite 2
definiert. Diese Zahlenfolge wird entsprechend mit der for-Schleife iteriert:
numbers = ""
for i in range(10, 21, 2):
numbers += str(i) + " "
print(numbers) # 10 12 14 16 18 20
Whitespace Sensitivität
Die Programmiersprache Python ist Whitespace sensitiv
. In Python wird Whitespace zur Gruppierung von Quellcodezeilen genutzt (zum Beispiel einen Schleifenkörper zu definieren). In anderen Programmiersprachen wie etwa Java, C oder JavaScript werden dazu geschweifte Klammern {}
verwendet. In Python zwingt dies vorallem Programmieranfänger:innen Quellcodeeinrückungen durchzuführen. Quellcodeeinrückungen gelten generell als Good-Practice
um die Lesbarkeit von Programmcode zu erhöhen.
Unter Softwareentwickler:innen sind die unterschiedlichen Stile und Einrückungsmöglichkeiten stark debatiert. Python gibt genau eine Form der Einrückung vor, dies führt bei Entwickler:innen immer wieder zu Kontroversen. Der Entwickler der Python Programmiersprache Guido van Rossum hat u.a. folgendes zur Einrückung von Programmabschnitten angemerkt:
Any individual creation has its ideosyncracies, and occasionally its creator has to justify these. Perhaps Python's most controversial feature is its use of indentation for statement grouping, which derives directly from ABC. It is one of the language's features that is dearest to my heart. It makes Python code more readable in two ways. First, the use of indentation reduces visual clutter and makes programs shorter, thus reducing the attention span needed to take in a basic unit of code. Second, it allows the programmer less freedom in formatting, thereby enabling a more uniform style, which makes it easier to read someone else's code. (Compare, for instance, the three or four different conventions for the placement of braces in C, each with strong proponents.)