Sie sind auf Seite 1von 143

Python ohne

Vorkenntnisse
Innerhalb von 7 Tagen ein
neuronales Netz programmieren
lernen

Benjamin Spahic
Inhalt
1. Vorwort und Einleitung ............................................................ 1
2. Vorbereitung – Interpreter und Texteditor installieren ........... 4
2.1. Der Texteditor................................................................... 4
2.2. Installation von Anaconda ................................................ 6
3. Programmierung - die wichtigsten Bausteine .......................... 9
3.1. Kommentare ..................................................................... 9
3.2. Docstrings ......................................................................... 9
3.3. Anweisungen .................................................................. 10
3.4. Konsolenausgabe mit print() .......................................... 11
3.5. Variablen......................................................................... 13
3.6. Datentypen ..................................................................... 16
3.7. Benutzereingabe mit input() .......................................... 19
3.8. Runden mit round........................................................... 20
3.9. Datentypumwandlung .................................................... 21
3.10. Operatoren ..................................................................... 22
3.11. Funktionen ...................................................................... 25
4. Datenspeicher und Verarbeitung ........................................... 27
4.1. Listen............................................................................... 27
4.2. Listen bearbeiten ............................................................ 31
4.3. Tupel ............................................................................... 34
4.4. Dictionaries ..................................................................... 35
4.5. Schleifen und Bedingungen ............................................ 36
4.6. if-Bedingung.................................................................... 37
4.7. While-Schleife ................................................................. 39
4.8. Die for-Schleife ............................................................... 41
4.9. Abbrechen mit break() ................................................... 43
4.10. Übungsaufgabe – Listen und Dictionaries ...................... 43
4.11. Lösung............................................................................. 44
4.12. Funktionen selbst erstellen ............................................ 46
4.13. Standard-Argumente setzen .......................................... 52
4.14. Funktionen in Modulen auslagern.................................. 54
4.15. Bibliotheken.................................................................... 57
4.16. Übungsaufgabe – Durchschnittnote berechnen ............ 59
4.17. Lösung............................................................................. 60
5. Objektorientieres Programmieren OOP ................................. 63
5.1. Klassen ............................................................................ 63
5.2. Kapselung von Klassen -public, protected, private ........ 67
5.3. Methoden ....................................................................... 70
5.4. Set und Get - Methoden ................................................. 71
5.5. __del__ Methode ........................................................... 72
5.6. Übung – Passwortschutz ................................................ 73
5.7. Lösung............................................................................. 73
5.8. Klassenvariablen ............................................................. 77
5.9. Übung - Durchschnittsgröße........................................... 79
5.10. Lösung............................................................................. 80
5.11. Vererbung ....................................................................... 82
5.12. Klassen auslagern ........................................................... 85
5.13. Übung – Lottospielen ..................................................... 87
5.14. Lösung............................................................................. 89
6. Grafische Oberflächen erzeugen ............................................ 93
6.1. Tkinter – verschiedene Bausteine .................................. 93
6.2. Optische Gestaltung der Fenster .................................. 105
6.3. Der grid-Manager ......................................................... 106
6.4. Place-Manager .............................................................. 108
6.5. Laden von PNG-Dateien ............................................... 109
6.6. Objekte farbig hervorheben ......................................... 111
6.7. Übung-Taschenrechner ................................................ 113
6.8. Lösung ........................................................................... 114
7. Künstliche Intelligenz und neuronale Netze ......................... 119
7.1. Ziel und Nutzen einer KI ............................................... 119
7.2. Aufbau eines neuronalen Netzes ................................. 121
7.3. Wie lernt ein neuronales Netz? .................................... 122
7.4. Datenstromoptimierte Programmierung ..................... 125
7.5. Arrays und numpy ........................................................ 131
Gratis eBook ......................................................................................... 138
1. Vorwort und Einleitung

In den letzten 50 Jahren hat die Menschheit eine Revolution erlebt, wie es in der
bisherigen Geschichte nur selten der Fall war.

Keine andere Entwicklung hatte einen so gigantischen Einfluss auf die Produkti-
vität und das Wohlbefinden der gesamten Weltbevölkerung.

Die Rede ist von der immer noch anhaltenden Digitalisierung. Dank dieses tech-
nischen Fortschritts können wir das Leben führen, wie wir es tun. Wir arbeiten
vor Bildschirmen oder kommunizieren mit Hilfe unseres Smartphones. Gleichzei-
tig stellen unzählige Fabriken voller Roboter und Förderbänder Waren und Güter
her.

Das alles ist nur durch jahrelange Forschung und Entwicklung und dem perfek-
ten Zusammenspiel aus Hardware und Software möglich. Zur Hardware gehö-
ren die Mikroprozessoren, Computer und elektrischen Bausteine, welchen
schließlich durch die angepasste Software, dem Aufspielen des Programms
bzw. des Programmcodes, Leben eingehaucht wird. Beides geht Hand in Hand
und ohne das eine ist das andere wertlos. Die Hardware wird immer erschwing-
licher. Gleichzeitig vervielfacht sich die Rechenleistung der Prozessoren.

Damit steigt auch die Nachfrage an Programmierern für die Maschinen und es
entstehen zahlreiche neue Arbeitsplätze auf diesem Sektor, die allerdings nicht
immer besetzt werden können. Große Firmen wie Bosch, Siemens oder SAP su-
chen seit Jahren permanent nach gut ausgebildeten, hochqualifizierten Infor-
matikern. Auch die namenhaften Autohersteller haben einen akuten Mangel an
Programmierern für ihre Steuereinheiten, Sicherheitssysteme etc.

Grund dafür ist ein schwerwiegendes Begeisterungsproblem in unserer Gesell-


schaft. Fast alle nutzen die Technik und profitieren vom Fortschritt, doch den
Willen, Elektrotechnik und Programmierung zu verstehen und ein Teil der Erfin-
dergemeinschaft zu werden, haben die Wenigsten.

Da du dieses Buch gekauft hast, scheinst du dich jedoch für genau dieses The-
mengebiet zu interessieren. Und das führt uns zum Kernthema dieses Buches –
die Programmierung in Python.

Python ist aktuell eine der einfachsten Programmiersprachen und wird daher im-
mer beliebter, sowohl im privaten Bereich als auch in der Industrie. Die Program-
mierung in Python ist anfängerfreundlich, anwendungsbasiert, schnell zu erler-
nen und es gibt eine große Community, deren Mitglieder bei Fragen zu bestimm-
ten Themen für einen Support zur Verfügung stehen. Wenn man an einer Stelle

Vorwort und Einleitung 1


stolpert, findet man im offiziellen Python-Forum, unzähligen Blogbeiträgen oder
YouTube-Videos eine Hilfe.

Vielleicht bist du ein Schüler, der sich mit der Programmierung eines Roboters
beschäftigt, ein Elektrotechniker, der mehr über die Software erfahren möchte
oder ein junggebliebener Pensionär, der sich allgemein für Programmierung in-
teressiert.

In jedem Fall wirst du es nicht bereuen, dich mit der Materie auseinanderzuset-
zen.

Gewiss gibt es viele Internetseiten und Bücher, die einen an das Thema Python-
Programmierung heranführen. Diese Bücher sind jedoch teilweise über 500 Sei-
ten stark und für Neueinsteiger vollkommen ungeeignet.

Wenn man sich bereits mit dem Thema etwas auskennt und Anhaltspunkte für
ein spezielles Projekt benötigt, können solche Lehrbücher hilfreich sein, aber für
einen Großteil der Interessenten sind diese weder erforderlich noch effektiv.

Und genau aus dieser Problemstellung heraus ist dieses Buch entstanden.

Es stellt einen Einsteigerratgeber für Interessenten dar, die ohne viel Vorwissen
die Grundkenntnisse der Python-Programmierung erlernen wollen, um
schnellstmöglich das erste eigene Projekt starten zu können.

Dazu werden zunächst folgende Fragen geklärt: Welche Programme und Biblio-
theken brauche ich? Wie programmiere ich meine eigenen Funktionen? Was gibt
es zu beachten? All das wird Schritt für Schritt erarbeitet und mit einem echten
Beispiel-Projekt abgerundet.

Der Name Python ist nicht von der Schlangenart abgeleitet, sondern von einer
britischen Kult-TV-Show Namens Monty Python‘s Flying Circus aus dem Beginn
der 70er Jahre.

Der niederländische Erfinder Guido van Rossum war ein großer Fan der Show.
Das spiegelt sich auch in vielen seiner Dokumentationen und Lernmaterialen zur
Programmiersprache wider, welche mit Zitaten aus der TV-Show versehen sind.

Voraussetzungen und Wissensstand:

Dieses Buch ist für jeden geeignet, der eine Grundbegeisterung für IT und Pro-
grammierung mitbringt. Die Grundkenntnisse der Programmierung wie Syntax,
Ablauf eines Programms etc. sind wichtig und werden deshalb in den ersten Ka-
piteln aufgeführt.

2 Vorwort und Einleitung


Programmiererfahrungen aus anderen Sprachen oder andere Vorkenntnisse
werden nicht vorausgesetzt. Diese Anleitung richtet sich auch explizit an Einstei-
ger und Programmier-Neulinge.

Zur besseren Struktur sind im Buch an bestimmten Stellen immer wieder fol-
gende Icons zu finden:

Glühlampe: Hier werden die Kernpunkte eines Kapitels zusammenge-


fasst. Diese Aussagen eignen sich gut zum Nachschlagen oder wenn
man ein Themengebiet noch einmal überfliegt.

Achtung: An dieser Stelle werden häufige Fehler erwähnt. Es wird er-


läutert, welche Hindernisse wo und warum auftreten können und wel-
che Annahmen oft fälschlicherweise vorliegen

Der Taschenrechner steht für Beispielrechnungen oder Verständnisfra-


gen zum Nachvollziehen und Verinnerlichen.

Notation in diesem Buch:

Fettgedruckte Begriffe: Begriffe, die neu eingeführt oder besonders hervorge-


hoben werden sollen.

Kursive Begriffe: Variablennamen, Funktionen und sonstige Begriffe, die vom


Fließtext abgehoben werden sollen.

Jetzt wünsche ich dir viel Spaß beim Lesen und Eintauchen in die Python-Pro-
grammierung.

Vorwort und Einleitung 3


2. Vorbereitung – Interpreter und Texteditor in-
stallieren
Python 3 ist der Nachfolger des im Jahr 2000 veröffentlichten und immer noch
weiter verbreiteten Python 2. Jedoch gewinnt das 8 Jahre jüngere Python 3 zu-
nehmend mehr Marktanteile und wird die Vorgängerversion langfristig ablösen.

Seit 2020 wird Python 2 nicht mehr weiterentwickelt bzw. unterstützt, weshalb
es für Neueinsteiger eindeutig die bessere Wahl ist, direkt mit Python 3 einzu-
steigen. Diese Version hat vor allem die Vorteile, dass es vollständig in Unicode
codiert. Das bedeutet, dass Sonderzeichen und Umlaute korrekt dargestellt wer-
den. Wir werden sehen, dass bei den Beispielen später immer wieder Umlaute
wie Ö, Ä, Ü vorkommen, ohne dass diese umgeschrieben werden müssen. Alles
in allem ist Python 3 die Zukunft. Große Unternehmen wie Instagram und Face-
book stellen gerade von Python 2 auf Python 3 um.

Um mit dem Programmieren starten zu können, müssen wir erst einmal einige
Software auf unserem Rechner installieren. Als erstes müssen wir die Pro-
gramme herunterladen, welche für die Python-Programmierung benötigt wer-
den. Dazu zählen ein Texteditor und ein Interpreter. Was genau ein Interpreter
ist, wird später noch genauer erklärt. Zunächst kümmern wir uns um den pas-
senden Texteditor.

2.1. Der Texteditor


Ein Programmcode ist nichts weiter als die Aneinanderreihung mehrerer Wörter,
Bezeichnungen und Variablen in einer bestimmten Form und mit definiertem
Aufbau.

Ein Programm (Quellcode) lässt sich zunächst einfach als ein mehrzeiliger Text
beschreiben.

Einen Programmcode kann man in einem gewöhnlichen Text-Edi-


toren öffnen und bearbeiten. Dazu braucht man kein spezielles
Programm.
Die logischen Folgen der Anweisungen werden im Anschluss durch die Interpre-
tation verständlich.

Zum Schreiben eines Programms in Python können wir also jeden beliebigen
Texteditor benutzen.

4 Vorbereitung – Interpreter und Texteditor installieren


Allerdings bietet sich der Einsatz eines Texteditors an, welcher für das Program-
mieren vorgesehen ist. Microsoft Word ist auch ein Textverarbeitungspro-
gramm, legt den Fokus jedoch klar auf die Optik eines Textes. Für eine Hausarbeit
oder ein Manuskript ist das hilfreich, für die Programmierung eher störend. Der
Grund dafür ist, dass alle Details wie Layout und Seitengröße ebenfalls in den
Dateien abgespeichert werden und diese somit für eine Programmierung unnö-
tig viele Informationen enthalten.

Der Standard-Windows-Editor (engl. „Notepad“) ist schon deutlich mehr auf Pro-
grammierung ausgerichtet, unterstützt jedoch viele, für die Programmierung
wichtige Funktionen nicht. Linux Benutzer haben mit dem gEdit bereits einen
umfangreichen Editor mit an Bord. Für Windows Benutzer, welche die meisten
von uns sein werden, empfiehlt sich hingegen das Tool NotepadPlusPlus (Note-
pad++). Das Programm ist für verschiedene Programmiersprachen geeignet. Sig-
nalwörter werden farbig hervorgehoben und einige Fehlermeldungen automa-
tisch erkannt. Der Nachteil dabei ist, dass man das Programm nicht direkt aus-
führen kann. Vor allem für Einsteiger ist eine schnelle ready-to-go Lösung rat-
sam.

Im Rahmen dieses Buches verwenden wir den Editor Anaconda. Dabei handelt
es sich um ein Open-Source-Projekt für die Programmiersprachen Python und R.
Anaconda wird auch an Schulen und Universitäten eingesetzt, da es besonders
anfängerfreundlich ist.

Anaconda ist ein Gesamtpaket aus der Entwicklungsumgebung Spyder


sowie dem Interpreter IPhython und weiteren Bausteinen. Damit spart
man sich auch die zusätzliche Installation eines Interpreters. Aber was
ist ein Interpreter überhaupt?

Ein Interpreter übernimmt, meist zusammen mit einem Compiler, die „Überset-
zung“ und Interpretation des Programmcodes. Die Arbeitsweise ist dabei kom-
plex und wird deshalb vereinfacht dargestellt. Im Grunde benötigt eine Program-
miersprache einen passenden, an sie angepassten Interpreter.

In unserem Fall nutzen wir daher IPython, welcher direkt mit Anaconda installiert
wird.

IPython wird später im Hintergrund unseren Programmcode in Befehle konver-


tieren, die der Computer anschließend ausführen kann.

Bevor wir zum ersten Programm kommen, müssen wir das Paket, das eine grafi-
sche Benutzeroberfläche und den Interpreter enthält, zunächst einmal downloa-
den. Das Tool wird von diversen Drittanbietern zur Verfügung gestellt, es emp-
fiehlt sich jedoch auch hier, Anaconda von der offiziellen Webseite herunterzu-
laden.

Vorbereitung – Interpreter und Texteditor installieren 5


2.2. Installation von Anaconda
Unter https://www.anaconda.com/products/individual kann die aktuelle Ver-
sion von Anaconda heruntergeladen werden.

Abbildung 1 Anaconda Installers

Hierfür können wir die für unser Betriebssystem passende Version auswählen.
Da Windows-Systeme am meisten verbreitet sind, wird die Installation anhand
von Windows gezeigt. Auf den anderen Plattformen ist die Vorgehensweise ana-
log.

Abbildung 2 Anaconda Setup

Nach der erfolgreichen Installation von Anaconda kann die Entwicklungsoberflä-


che Spyder geöffnet werden. Dazu suchen wir in der Windows-Suchleiste das
Programm Spyder. Das folgende Fenster öffnet sich.

6 Vorbereitung – Interpreter und Texteditor installieren


Abbildung 3 Benutzeroberfläche Spyder

Wie bereits erwähnt, handelt es sich hierbei um die Benutzeroberfläche, in der


wir unser Programm schreiben können. Gleichzeitig bietet Spyder als wissen-
schaftlich orientierte Umgebung viele weitere Vorteile.

Die Entwicklungsoberfläche Spyder bietet deutlich mehr Möglichkeiten,


als für einen Anfänger nötig sind. Es empfiehlt sich jedoch, sich gleich
an eine wissenschaftlich orientierte Entwicklungsumgebung zu gewöh-
nen, um später von den Vorteilen zu profitieren.

Spyder ist jedoch auch und vor allem für Einsteiger geeignet. Schlüsselwörter
werden automatisch erkannt und farbig dargestellt. Damit heben sich verschie-
dene Programmierelemente wie Variablen, Kommentare, Funktionen oder Klas-
sen voneinander ab. Was genau unter diesen Begriffen zu verstehen ist, wird in
den nächsten Kapiteln erklärt.

Abbildung 4 farbige Schlüsselworterkennung in Spyder

Normale Variablen und Befehle sind weiß hinterlegt. Kommentare werden auto-
matisch ausgegraut und Signalwörter werden eingefärbt.

Vorbereitung – Interpreter und Texteditor installieren 7


Nachdem Anaconda bzw. Spyder geöffnet ist, könnten wir theoretisch direkt los-
programmieren.

Zusätzliche In
Bilder, Grafiken etc.
Programmcode

Konsole
Benutzer Ein- und Ausgabe

Abbildung 5 Die verschiedenen Elemente von Spyder

Im linken Fenster wird der Programmcode geschrieben, im unteren rechten


Fenster ist die Konsole zu finden, die Schnittstelle zwischen Benutzer und Com-
puter. In der Konsole werden beispielsweise Fehlermeldungen ausgegeben.

Im oberen rechten Fenster werden weitergehende Informationen wie Abbildun-


gen oder Variablen dargestellt. Das ist vor allem für spätere Fehlersuche extrem
hilfreich und ein weiterer Vorteil von Spyder.

Um den hier geschriebenen Programmcode auszuführen, klicken wir auf den


großen, grünen Pfeil in der oberen Taskleiste. Dieser startet das Programm ein-
malig. Alternativ kann ein Programm durch STRG+ENTER ausgeführt werden. Die
anderen Symbole neben dem Startbutton haben andere Funktionen wie bei-
spielsweise den automatischen Neustart des Programms nach dem ersten
Durchlauf. Diese Schaltflächen sind für uns zunächst uninteressant.

Abbildung 6 Ausführen eines Programms

Vor Start sollte man das Programm in einem beliebigen Ordner abspei-
chern und einen sinnvollen Namen vergeben. Die Endung einer Python
Datei ist dabei immer .py

Bevor es an die konkrete Codeerstellung geht, wird der Aufbau eines Python-
Programms erklärt.

8 Vorbereitung – Interpreter und Texteditor installieren


3. Programmierung - die wichtigsten Bausteine
Im Folgenden werden die Grundlagen der Programmierung erläutert.

Spezieller werden die Bausteine wie das Benutzen von Kommentaren, Klammern
oder Einrücken anhand von Python beschrieben. Die Prinzipien lassen sich auch
auf andere Programmiersprachen wie Java, C, C# und weitere übertragen. Py-
thon hat jedoch den entscheidenden Vorteil, dass der Fokus auf Übersichtlich-
keit und Einfachheit gelegt wurde. Beispielsweise gibt es, anders als in anderen
Programmiersprachen, nur selten Klammern oder Semikolons.

3.1. Kommentare
Kommentare dienen der Übersichtlichkeit und Struktur eines Programms. Wenn
wir ein Programm verfassen und es anschließend jahrelang nicht mehr verwen-
den, werden wir später sehr lange brauchen, um die Funktionen wieder nachzu-
vollziehen.

Deshalb sind Kommentare für das schnelle Verständnis der Funktion eines Pro-
gramms enorm wichtig.

Kommentare dienen als Gedächtnisstütze, Strukturelement und zur Erläuterung


des Codes.

Ein Kommentar wird vom Compiler/Interpreter nicht übersetzt. Er dient


lediglich dem Menschen, um das Programm besser verstehen zu können.

Kommentare werden mit einem Raute-Zeichen angeführt.


# dies ist ein Kommentar

Kommentare werden vom Texteditor bzw. der Entwicklungsumgebung direkt als


solches erkannt. Sie werden in Spyder grau hinterlegt.

Es gibt keine feste Regel, wann wir einen Kommentar setzen sollten. Bei der Ent-
scheidungshilfe gilt der Spruch: „Lieber einen Kommentar zu viel als zu wenig“.
Andere Programmierer, welche unseren Code verstehen wollen, und auch wir
selbst werden später für jeden Kommentar dankbar sein.

3.2. Docstrings
Für eine bessere Übersichtlichkeit empfiehlt es sich, zusätzlich zu den Kommen-
taren, eine Beschreibung des Programms anzugeben. Diese Beschreibungen
werden als Docstring bezeichnet und machen es dem Programmierer leichter,
die Hintergründe und Funktionsweise des Programms zu verstehen. Docstrings

Programmierung - die wichtigsten Bausteine 9


können auch mit speziellen Funktionen ausgelesen werden, ohne dass auf den
Quellcode zugegriffen werden muss.

Vor allem, wenn mehrere Leute an einem Projekt arbeiten oder meh-
rere Personen denselben Code verstehen sollen, sind Kommentare und
Docstrings unumgänglich.

Ein Beispiel könnte wie folgt aussehen:


‘‘‘ Programmcode: Beispielprogramm Python

Automatisierung einer Sortierstation

Autor: Max Mustermann

Erstellt: 12.12.2021

Projektstand: 01.01.2022

’’’

Wie im obigen Beispiel zu sehen, wird die Kommentarsektion des Docstrings mit
drei einfachen ‘‘‘ oder drei doppelten Anführungszeichen “‘‘‘ geöffnet und ge-
schlossen. Die Funktion ist genau dieselbe.
“““ Alles innerhalb der Anführungszeichen wird als Überschrift/Beschreibung inter-
pretiert. “““

In der Benutzerumgebung Spyder werden Docstrings (grün) und Kommentare


(grau) automatisch erkannt und farbig hervorgehoben.

Beim Kopieren und Einfügen von Code, beispielsweise von Internetsei-


ten oder anderen Programmen, kann es vorkommen, dass die Anfüh-
rungszeichen nicht korrekt übernommen werden. Der Programmierer
muss diese dann löschen und erneut eingeben.

Jetzt wissen wir wie wichtig es ist, ein Programm ausreichend zu dokumentieren
und wie wir die Kommentare und Docstrings setzen. Als nächstes geht es an die
konkrete Programmierung Mittels Anweisungen.

3.3. Anweisungen
Anweisungen (engl. instructions) bilden den Kern eines Programms. „Anwei-
sung“ ist ein Überbegriff für beispielsweise Rechenoperationen oder Ein- oder
Ausgabebefehle an der Konsole. Auch das Definieren von Variablen, das Aufru-
fen von Funktionen oder das Abbrechen einer Schleife ist eine Anweisung. Bei
Anweisungen empfiehlt es sich, wieder einen Kommentar anzuhängen.

10 Programmierung - die wichtigsten Bausteine


Anweisungen können untereinandergeschrieben werden. Durch die
neue Zeile erkennt der Interpreter, dass es sich um eine neue Anwei-
sung handelt.
Anweisung1 #Kommentar zu Anweisung1

Anweisung2 #Kommentar zu Anweisung2

Anweisung3 #Kommentar zu Anweisung3

Alternativ können wir mehrere Anweisungen in dieselbe Zeile schreiben. Dabei


werden diese durch ein Semikolon getrennt. Das ist sinnvoll, wenn zwei Anwei-
sungen logisch eng zusammengehören oder wir oftmals die gleiche Anweisung
aufrufen.
Anweisung1 ; Anweisung2 #Kommentar zu Anweisung1 und 2

Als erste, einfach verständliche Anweisung wird der Aufruf der print()
Funktion eingeführt.

3.4. Konsolenausgabe mit print()


Die print()-Funktion ist einer der einfachsten und am meisten genutzten
Funktionen. Mit ihrer Hilfe kann man Werte an der Konsole ausgeben.
Damit haben wir eine Möglichkeit, um mit dem Benutzer des Programms
zu „kommunizieren“.

Mit dem Befehl print() können Wörter und Zahlen an der Konsole ausgegeben
werden, ebenso wie der Inhalt von Variablen, Listen oder ganzen Datensätzen,
welche im folgenden Kapitel behandelt werden.

Im ersten Beispiel übergeben wir der Funktion einen Text, der dem Benutzer an-
gezeigt werden soll. Diesen Text setzen wir bei der print()-Funktion zwischen die
runden Klammern.

Der auszugebende Text wird innerhalb der Klammern in einfachen oder doppel-
ten Anführungszeichen gesetzt.
print(“Hallo Welt“) #gibt Hallo Welt in der Konsole aus

Nicht vergessen, damit das Programm startet, muss es über die Schalt-
fläche mit dem grünen Pfeil ausgeführt werden.

Möchte man die doppelten Anführungszeichen mit ausgeben, können einfache


Anführungszeichen vorangestellt werden.
print(‘“Hallo Welt“‘) #gibt “Hallo Welt“ aus

Programmierung - die wichtigsten Bausteine 11


Wie bereits erwähnt, können wir nicht nur reinen Text ausgeben, sondern auch
Zahlen oder ganze Rechnungen.
Anders als beim Text, werden beim Ausgeben einer Rechnung die Anführungs-
zeichen weggelassen. Somit wird das Ergebnis der mathematischen Operation
ausgegeben und nicht die Textzeichen der Rechnung. Ein Beispiel verdeutlicht
das:
print(“3+4“) #Es wird 3+4 ausgegeben

print(3+4) #Es wird 7 ausgegeben

Abbildung 7 print-Ausgabe in der Konsole

Praktisch ist dabei, dass nach einem print()-Befehl automatisch ein Umbruch in
der Konsole eingefügt wird.

Zur Darstellung der Ausgabe stehen uns verschiedene Möglichkeiten zur Verfü-
gung.

Für ein geordnetes Erscheinungsbild können bei der Ausgabe der Daten über ei-
nen leeren print()-Befehl zusätzlich Absätze und Leerzeilen eingefügt werden.
print() #Leerzeile

Ein Zeilenumbruch kann durch die Zeichenfolge \n realisiert werden, eine Einrü-
ckung (Tabulator) mit der Zeichenfolge \t .
print('Absatz folgt\n') #Absatz

print('Leerzeile folgt')

print() #Leerzeile

print("\t Dieser Text ist eingerückt" )

Abbildung 8 Beispiel print-Ausgabe eines Absatzes, Leerzeichen und einer Einrückung

Alternativ kann ein print()-Befehl auch über mehrere Zeilen ausgegeben werden.

Dafür werden drei Anführungszeichen am Anfang und am Ende des Textes be-
nötigt, genau wie bei einem Docstring.

12 Programmierung - die wichtigsten Bausteine


Anschließend werden die Zeilenumbrüche auch in der Konsole ausgegeben.
print('''dieser Text

wird

in 4 Zeilen

ausgegeben''')

Abbildung 9 print-Ausgabe über mehrere Zeilen

Nachdem wir gelernt haben, wie man einfachen Text oder Zahlen mittels der
print()-Funktion ausgibt, beschäftigen wir uns als nächstes mit dem Speichern
von Daten in Variablen.

3.5. Variablen
Variablen sind unverzichtbar für nahezu jedes Python-Programm. Dabei handelt
es sich um Zahlen, Zeichen oder ganze Texte, die während der Laufzeit eines Pro-
gramms verändert werden können. Sie dienen zur Speicherung von Werten.
Durch Nennen der Variablen können wir im Verlauf des Programms den Wert
wieder abrufen, beispielsweise um diesen in einer Rechnung einzusetzen.

Eine Variable besteht aus einem Namen und einem Wert. Wir können uns die
Variable wie eine Box vorstellen, auf der der Name der Variablen geschrieben
ist. Der Inhalt ist dabei der Wert der Variablen. Dieses Verständnis wird später
noch von Bedeutung sein.

Zum Anlegen einer Variablen schreiben wir lediglich den Namen der ge-
wünschten Variablen und weisen ihr mit dem Gleichheitszeichen (Zu-
weisungsoperator) direkt einen Wert zu.

Anders als bei anderen Programmiersprachen müssen wir Variablen in Python


am Anfang eines Programms nicht initialisieren. Im Gegenteil, einer Variablen
muss bei der erstmaligen Nennung direkt ein Wert zugewiesen werden.

Der Name der Variablen kann bei der Erstellung beliebig gewählt werden und
Buchstaben, Ziffern und Unterstriche enthalten. Allerdings nicht mit einer Ziffer
begonnen werden.
variable_test_1 = 4

Programmierung - die wichtigsten Bausteine 13


Dabei ist variable_test_1 der Name der Variablen, und die Ziffer 4 ihr In-
halt/Wert.

4
variable_test_1

Abbildung 10 Variablen-Box-Modell

Es gibt einige Konventionen bei der Erstellung von Variablennamen, welche es


einem Programm ermöglichen, innerhalb weniger Sekunden zu erkennen, wel-
ches Wort eine Variable und welches z.B. eine Klasse darstellt.

Die wichtigsten Konventionen sind dabei:


• Der Name einer Variablen soll deren Funktion widerspiegeln.

• Variablen beginnen mit einem Kleinbuchstaben.

• Variablen, die aus mehreren Wörtern bestehen, werden mit einem


Unterstrich verbunden

• Lange Wörter sollen nach Möglichkeit abgekürzt werden.

Die Benennung der Variablen sollte sinnvoll und kurz sein. Bei mehreren
ähnlichen Variablen empfiehlt es sich, diese durch den Namen oder an-
hand von Indizes zu unterscheiden. Eine Variable, in der beispielsweise
ein Temperaturwert gespeichert wird, könnte demnach temp1 heißen.
temp1 = 20

temp2 = 30

Der Variablen temp1 (beispielsweise in einem Innenraum) wird der Wert 20 zu-
geordnet. Der Variablen temp2 (beispielsweise im Außenbereich) entsprechend
der Wert 30.

Die Variablen müssen eindeutige Namen erhalten, ein Name darf nicht
mehrmals vergeben werden. In Python wird zusätzlich in Groß- und
Kleinschreibung unterschieden. Temp1, TEMP1 und temp1 werden als
drei verschiedene Variablen interpretiert.

Variablen können auch Wörter (Zeichenketten) enthalten.

14 Programmierung - die wichtigsten Bausteine


name = ‘Tom‘

Wenn wir Wörter oder Sätze in einer Variablen speichern wollen, müssen wir
immer Anführungszeichen setzen. Dabei können wir einfache oder doppelte An-
führungszeichen verwenden. Die Funktion ist die gleiche.
name = ‘Tom‘

name = “Tom“

Anders als im Deutschen, müssen beide Anführungszeichen oben stehen.

Der Wert einer Variablen kann ebenfalls mit dem print() Befehl ausgegeben wer-
den.
print(temp1)

Bei der Ausgabe von Variablen über die print()-Funktion gibt es hinsichtlich der
Syntax einiges zu beachten.

Möchte man den Inhalt einer Variablen ausgeben, werden keine Anfüh-
rungszeichen geschrieben. D.h. ohne Anführungszeichen wird von dem
Befehl print() eine Variable erwartet, die definiert sein muss.

Soll dagegen der Text ausgegeben werden, sind Anführungszeichen zu


setzen. In der nachfolgenden Tabelle wird dies anhand einiger Beispiele
veranschaulicht. Zunächst wird der Variablen name der Wert Tom zu-
gewiesen.
name=‘Tom‘ # Der Variable „Name“ wird der Inhalt ‘Tom‘ zugewiesen

print(‘name‘) gibt „name“ aus

print(name) gibt „Tom“ aus

print(Tom) Error, die Variable „Tom“ ist nicht definiert

Der letzte Aufruf gibt einen Error aus, weil keine Anführungszeichen ge-
setzt sind. Die Funktion fordert an dieser Stelle eine Variable. Die Vari-
able Tom ist jedoch nicht bekannt. Tom ist lediglich der Inhalt der Vari-
ablen name. Das ist ein wichtiger Unterschied.

Die print()-Funktion kann auch eine Kombination aus Text und Variablen anzei-
gen. Dafür müssen nicht mehrere Befehle aufgeführt werden.

Wollen wir beispielsweise die Temperatur inklusive der Einheit °C angeben, kön-
nen wir beides in einen print()-Befehl packen. Die Syntax dabei ist:
print(“TEXT“,VARIABLE,“TEXT“)

Programmierung - die wichtigsten Bausteine 15


Dabei werden die Bereiche mit einem Komma getrennt.

Für das Beispiel der Temperatur sieht das folgendermaßen aus:


temp1=20

print('Temperatur: ',temp1,'°C')

Der Text wird einfach über das Setzen in Anführungszeichen der Variablen hin-
zugefügt.

Was passiert jedoch, wenn wir ein Anführungszeichen speichern oder ausgeben
möchten?

Hierfür muss dem Interpreter mitgeteilt werden, dass es sich um Anführungszei-


chen handelt, die als Text anzusehen sind. Dafür schreiben wir vor das Anfüh-
rungszeichen einen Backslash (\). Dieser kann mit der Tastenkombination
AltGr+ß aufgerufen werden. Diese Vorgehensweise wird auch als Maskierung
bezeichnet.

Das Anführungszeichen wird wie folgt maskiert:


variable = ‘Dieses Anführungszeichen \‘ wurde maskiert.‘

print(variable)

Abbildung 11 Ausgabe eines maskierten Anführungszeichens

Jetzt wissen wir, wie wir Zahlen oder Worte in Variablen speichern und diese
über die Konsole ausgeben können. Damit haben wir bereits viel gewonnen. Im
nächsten Kapitel beschäftigen wir uns mit Datentypen von Variablen und deren
Einteilung.

3.6. Datentypen
In jeder Programmiersprache gibt es verschiedene Variablentypen, die sich hin-
sichtlich ihrer Größe (Speicherplatzbedarf) oder dem Inhalt unterscheiden.

Man spricht dabei von Datentypen. Verschiedene Daten werden nach ihrer Art
und ihrer Funktion eingeteilt. Eine Zahl hat dabei beispielsweise einen anderen
Typ als ein Wort. Doch wozu braucht man diese Unterscheidung überhaupt?

16 Programmierung - die wichtigsten Bausteine


Wenn eine Variable beispielsweise nur die Werte 0 oder 1 enthalten kann, reicht
schon eine einzelne Speicherzelle (Bit) aus, um die Information abzubilden. Als
Beispiel kann ein Münzwurf gewählt werden, dessen Ergebnis lediglich 1 (Zahl)
oder 0 (Kopf) annehmen kann.

Es macht daher keinen Sinn, der Variablen 2, 3 oder 10 Speicherzellen bereitzu-


stellen. Daher weist man der Variablen einen Datentyp zu, welcher lediglich eine
Speicherzelle belegt und nur zwei Werte annehmen kann.

Neben dem Haushalten mit Speichereinheiten gibt es noch weitere Gründe, wa-
rum es sinnvoll ist, Daten in verschiedenen Typen abzuspeichern.

So können beispielsweise Zahlen mit Hilfe von Operatoren verrechnet werden.


3 + 3 = 6 ist jedem bekannt und logisch geläufig. Für den Datentyp „ganze Zah-
len“ gibt es daher einen eigenen Typ.

Ganze Zahlen werden als Integer, kurz int, abgespeichert. Der Interpre-
ter weiß: Mit Integer-Variablen kann man rechnen.

Aber wie sieht es zum Beispiel mit Worten aus?

Der Datentyp für Wörter heißt string. Mit ihm kann man nicht so ein-
fach rechnen wir mit Integer-Variablen.

Ein simples Beispiel veranschaulicht die Problematik.


„Hallo“ + “Welt“ # Was ergibt das?

Man könnte den Ausdruck als „Hallo Welt“ interpretieren, eine mathematische
Grundlage gibt es dafür nicht. Noch deutlicher wird es bei einem Vergleich.
„Hallo“ < „Welt“ # Was ergibt das?

Dies verdeutlicht, dass man arithmetische oder logische Operatoren nicht auf
string-Variablen anwenden kann.

Das Verständnis der Unterschiede ist für spätere Kapitel noch essenziell.

Neben den beiden Datentypen string und int gibt noch weitere. In der folgenden
Tabelle sind die wichtigsten Variablentypen mit ihren Eigenschaften aufgelistet.
Darüber hinaus gibt es unzählige weitere Variablentypen, die für Neueinsteiger
aber nur eine geringe bis überhaupt keine Rolle spielen.

Programmierung - die wichtigsten Bausteine 17


Name Abkürzung Darstellung Besonderheit

boolean bool 0 und 1


(True or False)

string str “Hallo” Zeichenketten

integer int -1, 5, 1929 Nur ganze Zahlen

float float 1.32 ; 6.00 ; 128.28 (Gleit-)Kommazahlen

Liste list [1,18,’Hallo’] Mehrere Elemente

In anderen Programmiersprachen muss man dem Compiler mitteilen, welchem


Datentyp eine Variable zugeordnet wird.

Nicht so bei Python. Der Vorteil von Python liegt vor allem in der einfachen Zu-
ordnung von Datentypen. Python erkennt anhand der Variablen selbst, welcher
Datentyp verwendet werden soll. Durch den Inhalt bzw. die Schreibweise des
Inhalts wird automatisch ein Datentyp zugewiesen, ohne dass dieser separat an-
geben werden muss.
x=5 # Variable wird als Ganzzahl (integer) abgespeichert

x = 5.00 # Variable wird als Gleitkommazahl (float) abgespeichert

x = “5.00“ # Variable wird als Zeichenkette (string) abgespeichert

Datentypen sind nicht starr. Das heißt, sie können auch innerhalb des
Programms verändert werden.

Python passt auch hier bei Bedarf den Datentyp an. Wird eine ganze Zahl (int)
mit einer Gleitkommazahl (float) verrechnet, wird dem Ergebnis automatisch
auch eine Gleitkommazahl (float)zugewiesen.
i = 52 # Der Datentyp wird automatisch zu Integer gesetzt

i = 52 + 0.01 # Der Datentyp wird auf float geändert.

i = "zweiundfünfzig" # Der Datentyp ist jetzt ein string

18 Programmierung - die wichtigsten Bausteine


Dabei besitzt jeder Datentyp verschiedene Attribute (Eigenschaften). Das wird
im Kapitel Funktionen noch von Bedeutung sein, denn nicht jede Funktion ak-
zeptiert alle Datentypen.

Bei Spyder kann man sich die Variablen und deren Inhalt sowie den Da-
tentyp anzeigen lassen. Das ist vor allem bei der Suche nach Fehlern
sehr hilfreich. Unter dem Punkt Variable Explorer im oberen, rechten
Feld werden der Variablenname, der Datentyp sowie Länge und Inhalt
der Variablen angezeigt.

Abbildung 12 Datentypen in Spyder anzeigen lassen

Im angezeigten Beispiel handelt es sich um den Datentyp Integer (int).

Es empfiehlt sich, ein paar Überlegungen zu den Datentypen anzustellen. Was


für ein Typ ergibt sich, wenn wir 6 geteilt durch 3 rechnen? Welcher, wenn wir 7
durch 3 dividieren?

3.7. Benutzereingabe mit input()


Wie wir Daten an der Konsole ausgeben, haben wir bereits kennengelernt. Als
nächstes sehen wir uns an, wie wir Daten vom Benutzer abfragen können.

Die Funktion input() erfüllt genau diesen Zweck. Sie ist hilfreich, um den
Benutzer des Programms während der Laufzeit miteinzubeziehen.

Der Funktion kann man zusätzlich eine Aufforderung als Argument übergeben.
input(“Bitte geben Sie eine Zahl zwischen 0 und 10 ein“)

Sobald das Programm die Funktion ausführt, wird die Aufforderung in der Kon-
sole ausgegeben und es verlangt nach einer Benutzereingabe. Die Benutzerein-
gabe erfolgt ebenfalls über die Konsole. Es können eine Zahl, ein Wort oder sogar

Programmierung - die wichtigsten Bausteine 19


Sätze eingetippt werden. Durch Betätigen der Enter-Taste werden die Daten ein-
gelesen.

Die Funktion input() speichert die Dateneingabe als Zeichenkette ab. Für Wörter
oder Sätze ist das korrekt und kann so übernommen werden.

Möchte man jedoch Zahlen einlesen, um mit diesen anschließend zu


rechnen, muss man die Funktion eval() verwenden.

Die Funktion eval() speichert die eingelesenen Daten unter dem richti-
gen Datentyp ab. Denn wir erinnern uns, dass man mit string-Variablen
nicht rechnen kann.

Jetzt wird es etwas komplizierter: Wir übergeben der Funktion eval() die kom-
plette Funktion input() als Argument. Wir schachteln die Funktionen ineinander.

Möchten wir einen eingegeben Wert in einer Variablen mit dem passenden Da-
tentyp speichern, lautet der vollständige Befehl:
x= eval(input(“Bitte geben Sie eine Zahl zwischen 0 und 10 ein“))

Damit wird die Aufforderung ausgeben, anschließend die Zahl eingelesen und in
den passenden Datentyp (integer) umgewandelt und in die Variable x gespei-
chert.

3.8. Runden mit round


Bei der Verarbeitung und dem Einlesen von Zahlen kommt es öfter vor, dass eine
Zahl als Gleitkommazahl gespeichert wird. Der Datentyp float ist auf mehrere
Nachkommastellen genau. Für das Rechnen sehr praktisch, bei der Bildschirm-
ausgabe ist das optisch äußerst unschön.

Ein einfaches Beispiel veranschaulicht die Problemstellung.


y= 5/3

print(y)

Abbildung 13 Ausgabe einer float-zahl

Die round()-Funktion schafft Abhilfe. Der Syntax ist wie folgt

round(Die zu rundende Zahl, Anzahl der Nachkommastellen)


y=5/3

20 Programmierung - die wichtigsten Bausteine


print(round(y,2)) # y wird auf 2 Nachkommastellen gerundet.

Abbildung 14 Ausgabe einer gerundeten float-Zahl

Es gibt noch viele weitere Funktionen, von denen wir auch noch weitere ken-
nenlernen und sogar selbst verfassen werden. Davor sehen wir uns jedoch
noch einmal genauer an, wie man Daten effektiv speichern und verarbeiten
kann.

3.9. Datentypumwandlung
Wir haben bereits verschiedene Datentypen kennengelernt und wie Python
diese verarbeitet. Meistens wird automatisch der richtige Datentyp angelegt.
Wir haben aber auch schon ein Beispiel gesehen, bei dem das nicht der Fall ist.
Die input()-Funktion liefert nicht immer den Datentyp, den wir uns wünschen.
Als Lösung haben wir die eval()-Funktion verwendet, welche die Eingabe evalu-
iert und den richtigen Datentyp zuordnet.

Für Einsteiger ist die Funktion vollkommen ausreichend. Erfahrene Entwickler


raten hingegen oftmals von der Verwendung ab. Grund dafür ist, dass die Funk-
tion mehr Rechenleistung und Laufzeit als die manuelle Eingabe des Datentyps
verlangt.

Außerdem ist die Auswertung des eingegebenen Ausdrucks mit der eval()-Funk-
tion teilweise sogar gefährlich. Ein Bediener kann einen Ausdruck eingeben, des-
sen Auswertung durch die Funktion Schäden auf dem Rechner, auf dem das Pro-
gramm läuft, verursacht. In der Praxis wird eval() nur eingesetzt, wenn das Pro-
gramm von niemand anders als dem Programmierer bedient wird.

Als Alternative können wir die Datentypen auch vorgeben, indem wir den Daten-
typ vor den auszuführenden Befehl schreiben. Wollen wir eine Eingabe als Inte-
ger-Zahl abspeichern, schreiben wir:
x= int(input("geben sie eine Zahl ein"))

die Zahl erhält den Datentyp int.

Die Typumwandlung kann auf alle Datentypen angewandt werden.


x= int(input("geben sie eine Zahl ein")) #int

print(x)

y=float(x) #Umwandlung in Gleitkommazahl

print(y)

Programmierung - die wichtigsten Bausteine 21


z=str(y) #Umwandlung in Zeichenkette

print(z)

An der Konsole können wir die Ausgabe anschauen.

Abbildung 15 Ausgabe nach Typumwandlung

Die zweite und dritte Ausgabe ist identisch, jedoch ist einmal der Datentyp float
ausgegeben worden und einmal eine Zeichenkette. Das zeigt auch der Variablen-
Manager in Spyder.

Abbildung 16 Datentypen nach Typumwandlung

3.10. Operatoren
Wir haben bereits Variablen und Datentypen kennengelernt und können die ab-
gespeicherten Werte nicht nur mit der print()-Funktion ausgeben, sondern auch
mit ihnen rechnen oder verschiedene Variablen miteinander vergleichen.

Hierfür werden verschiedene Operatoren verwendet, die man in unterschiedli-


che Klassen einteilen kann. Die Operatoren sind teilweise logisch erschließbar
wie beispielsweise das Plus- und Minuszeichen.

Die Operatoren wie plus, minus, mal und geteilt und weitere werden
arithmetische Operatoren genannt.

Die folgende Tabelle zeigt die häufigsten arithmetischen Operatoren in Python


und deren Funktion.

22 Programmierung - die wichtigsten Bausteine


Arithmetische Operatoren

Operator Bedeutung Beispiel Funktion

= Zuweisung x=3

+ Addition x=y+2

- Subtraktion x=y-2

* Multiplikation x=y*2

/ Division x=y/2

** Exponentation y=x**3 y=x³

% Modulo x = 10%3 Liefert den Rest bei Division.


10 geteilt durch 3 ergibt 3,
Rest 1, also nimmt x den Wert
1 an.

// Ganzzahldivision x = 10//3 Liefert das Ganzzahlergebnis


bei einer Division.
10 geteilt durch 3 ergibt 3.
Der Rest wird nicht berück-
sichtigt.

Neben den arithmetischen Operatoren, welche zum Rechnen dienen, gibt es


noch weitere, beispielsweise die Vergleichsoperatoren.

Im Gegensatz zu den arithmetischen Operatoren ist die Wirkungs-


weise der Vergleichs-Operatoren binär, das bedeutet, es gibt lediglich
zwei mögliche Ergebnisse.

Auf die Frage: „Ist der Inhalt der Variable x größer als die Zahl fünf?“ gibt es nur
zwei Antwortmöglichkeiten. Entweder stimmt die (Un-)Gleichung und ist damit
wahr (True) oder sie stimmt nicht und ist damit falsch (False).

Das Ergebnis eines Vergleichs kann lediglich zwei Zustände annehmen -


wahr oder falsch.

Programmierung - die wichtigsten Bausteine 23


Möchte man zwei Zahlen oder Variablen miteinander vergleichen, benötigt man
daher die Vergleichsoperatoren.

Die folgende Tabelle veranschaulicht noch die Verwendung von Vergleichsope-


ratoren und deren Ergebnis.

Vergleichsoperatoren
Operator Bedeutung Beispiel Ergebnis

< Kleiner? 3<5 True

<= Kleiner gleich? 5<=3 False

> Größer? 5>3 True

>= Größer gleich? 5>=3 True

== Gleich? 5==4 False

!= Ungleich? 4!=5 True

Das einfache (=) Gleichheitszeichen ist eine Zuweisung. Möchte man


prüfen, ob zwei Variablen gleich sind, müssen zwei Gleichheitszeichen
(==) gesetzt werden.
x=5 # Der Variablen x wird der Wert 5 zugewiesen

x==5 # Es wird geprüft, ob x den Wert 5 enthält. Das Ergebnis ist True oder False

Der Befehl print(3<4) gibt als Ergebnis „True“ also „wahr“ aus.

Warum sind hier keine Anführungszeichen gesetzt? Was würde die Kon-
sole ausgeben, wenn man diese einfügt?

Lösung: Wenn Anführungszeichen eingesetzt werden, wird der Text und nicht das
Ergebnis der Operation ausgegeben. In dem Fall print(“3<4“) würde 3<4 ausge-
geben.

Als letzten Unterpunkt schauen wir uns die logischen Operatoren an. Logische
Operatoren interpretieren jeden Zahlenwert und jede Variable als wahr oder
falsch, ähnlich wie bei den Vergleichsoperatoren. Dabei wird jeder Wert außer
der Null als True interpretiert. Lediglich die Null wird als False angenommen. Lo-
gische Operatoren werden meist mit Bedingungen kombiniert.

Die Besonderheit bei den logischen Operatoren ist, dass der Operator selbst kein
Zeichen, sondern ein Wort ist.

24 Programmierung - die wichtigsten Bausteine


Die wichtigsten Operatoren werden in der folgenden Tabelle dargestellt.

Logische Operatoren
Operator Bedeutung Beispiel Funktion

not Negation x = not y; Ist y wahr, wird x falsch


und umgekehrt

and Und x = y and z Wenn y und z wahr


sind, ist x wahr, ansons-
ten ist x falsch

or Oder x =y or z Wenn y oder z wahr


sind, ist x wahr, an-
sonsten ist x falsch

Was ist jeweils der Wert der Variablen z?


Die Zahl 5 wird als „True“ interpretiert. Demnach erhält
x=5 die Variable z den Wert „False“
z = not x
x=6;y=0 x ist „True“, y jedoch nicht. Demnach ist die Variable z
z = x and y „False“.

x=6;y=0 x ist „True“, y ist „False“. Es reicht, wenn x oder y „True“


z = x or y ist. Daher ist z auch „True“

x=6;y=0 x ist „True“, y ist „False“. „not y“ ist daher „True“. Dem-
z = x and not y nach ist die Variable z auch „True“

Hiermit haben wir einen Überblick zu den wichtigsten Bauteilen beim Rechnen
mit Variablen erhalten. Operatoren und Variablen sind Grundbausteine eines je-
den Programms und werden in vielfachen Kombinationen und Möglichkeiten
eingesetzt. Um die Operatoren und Variablen sinnvoll verwenden zu können,
schauen wir uns im nächsten Unterkapitel die Wirkungsweise von Funktionen in
Python an.

3.11. Funktionen
Funktionen wurden teilweise bereits eingeführt, beispielsweise die print()-Funk-
tion, welche Daten an der Konsole ausgibt. Den meisten sind Funktionen noch
aus dem Schulunterricht in Erinnerung geblieben: 𝑦 = 2 · 𝑥 + 1 ist ein Beispiel
einer Funktion.

Programmierung - die wichtigsten Bausteine 25


Der Grundgedanke dabei ist, dass wir der Funktion eine Zahl x übergeben und
anschließend eine Zahl y zurückbekommen.

Bei der Programmierung beschränkt sich eine Funktion jedoch nicht nur
auf Zahlen als Ein- oder Ausgabewerte.

Beispielsweise kann man einer Funktion einen Buchstaben oder ein ganzes Wort
anstelle einer Zahl übergeben. Der übergebene Wert wird als Argument bezeich-
net.

Eine Funktion wird über den Namen, gefolgt von zwei runden Klam-
mern, aufgerufen. Die Klammern enthalten die geforderten Argumente
der Funktion.

Zurück bekommt man ebenfalls nicht zwangsläufig eine Zahl.

Als Beispiel wird wieder unsere bekannte Funktion print() herangezogen.

Der Funktion print() kann man Variablen, Terme oder Sätze übergeben.

Funktion print()

‘Hallo Welt‘ Konsolenausgabe


=> Argument/Übergabewert
„Rückgabewert“

print( ‘Hallo Welt‘ )

Abbildung 17 Funktionsaufruf

Als Rückgabewert wird eine Konsolenausgabe angestoßen.

Die print()-Funktion ist nur ein Beispiel einer Funktion, als nächstes schauen wir
uns weitere, sehr nützliche Funktionen an.

26 Programmierung - die wichtigsten Bausteine


4. Datenspeicher und Verarbeitung
4.1. Listen
Python ist hervorragend dafür ausgelegt, um mit großen Datensätzen zu arbei-
ten. Mit einfachen Variablen kommen wir jedoch schnell an unsere Grenzen.
Wenn wir hunderte Zahlen speichern wollen, müssten wir hunderte Variablen
anlegen. Sinnvoller ist es, mehrere zusammenhängende Variablen in einer Vari-
ablen zu speichern. Als Lösung wird ein neuer Datentyp eingeführt, die soge-
nannten Listen.

Dabei handelt es sich, wie der Name schon sagt, um eine Liste, also eine Anei-
nanderreihung von Wörtern oder Zahlen, die zusammen in einer einzigen Vari-
ablen gespeichert werden.

Das Anlegen einer Liste erfolgt analog zum Anlegen einer Variablen, mit dem Un-
terschied, dass bei Beginn und am Ende der Liste eckige Klammern stehen.
Dadurch weiß der Interpreter, dass es sich um eine Liste handelt.

Die Elemente der Liste werden durch Kommata getrennt. Bei Wörtern
(strings) dürfen wiederum die Anführungszeichen nicht vergessen wer-
den.
datensatz = [ “Tom“, 26, 1.84]

Das Beispiel legt eine Liste mit den drei Elementen an und speichert die Liste in
die Variable datensatz. Die Variable besitzt jetzt den Datentyp liste. Tom steht
dabei für den Namen, 26 für das Alter und 1.84 für die Größe.

Normalerweise hätten wir drei gesonderte Variablen anlegen müssen. Der Vor-
teil von Listen liegt also auf der Hand.

Anhand des Beispiels können wir auch noch weitere Eigenschaften ableiten.

Wie man schnell sieht, kann eine Liste verschiedene Datentypen, hier
string/str, int und float enthalten. Jedes Element der Liste erhält dabei
automatisch einen Index, beginnend bei Null.

Möchte man einzelne Elemente einer Liste abfragen, muss der Index in Klam-
mern geschrieben werden.

print(datensatz[0]) gibt das erste Element [„Tom“] aus

print(datensatz[2]) gibt das dritte Element [1.84] aus

Datenspeicher und Verarbeitung 27


print(datensatz[:1]) gibt eine Teilliste [“Tom“] aus

print(datensatz[1:2]) gibt eine Teilliste [26, 1.84] aus

print(datensatz[-1]) gibt das letzte Element [1.84] aus

print(datensatz[-2]) gibt das vorletzte Element [26] aus

Wie können wir den Index -1 und -2 interpretieren? Es gibt doch kein negatives
Listenelement, oder?

Nun, die Listen können schnell viele hunderte Elemente besitzen oder es können
ständig neue Elemente angehängt werden.

Möchten wir auf die letzten Elemente zugreifen, können wir den letzten Index
eingeben. Manchmal ist der Index jedoch nicht bekannt oder er ist sehr groß.
Deshalb kann man in Python mit negativen Indexen die zuletzt angefügten Ele-
mente auswählen.
liste = [0,1,….,999999999]

#Wir wollen das 999.999.999te Element auslesen

liste[999999999]# funktioniert

liste [-1] #besser

Rechnen mit Listen:


Listen können Elemente mit verschiedenen Typen enthalten. Wir können aber
auch mit der ganzen Liste, also dem kompletten „Datensatz“ auf einmal rechnen.
Beispielsweise können wir einer Liste beliebige Elemente hinzufügen, diese
überschreiben oder löschen. Als Beispiel nehmen wir wieder unsere Liste mit Na-
men, Alter und Größe einer Person heran:
datensatz = [ “Tom“, 26, 1.84]

Durch den Befehl


datensatz[1] = 27

wird das Alter von 26 auf 27 überschrieben.

Mit dem Befehl


del datensatz[1]

wird das Element mit dem index 1 vollständig gelöscht.

28 Datenspeicher und Verarbeitung


Addieren und Multiplizieren

Obwohl Listen oftmals Wörter oder Sätze enthalten, kann man sie trotzdem ad-
dieren, multiplizieren oder verschachteln. Bei der Addition von Listen gilt folgen-
des zu beachten:

Wird ein einzelnes Element oder eine Liste zu einer anderen Liste ad-
diert, werden lediglich die einzelnen Elemente an das Ende der beste-
henden Liste gehängt.
datensatz1 = [ “Tom“, 26,1.84]

datensatz2 = [“Lisa“,28,1.67]

datensatz3 = datensatz1 + datensatz2

print(datensatz3)

 ['Tom', 26, 1.84, 'Lisa', 28, 1.67]

Es können auch einzelne Elemente angehängt werden.


datensatz3 = datensatz1 + [“neues Element“]

print(datensatz3)

 ['Tom', 26, 1.84, 'neues Element']

Bei der Multiplikation mit einer Zahl n wird die bestehende Liste n-mal
dupliziert und angehängt. Beispiel für n=3:
datensatz3 = datensatz1*3

print(datensatz3)

 ['Tom', 26, 1.84, 'Tom', 26, 1.84, 'Tom', 26, 1.84]

Mehrdimensionale Listen
Neben Wörtern und Variablen können die Elemente einer Liste selbst Listen sein.
Diese Listen können wiederum Listen als Elemente enthalten und so weiter und
so weiter.

Man spricht dabei auch von mehrdimensionalen Listen.

Um eine mehrdimensionale Liste zu erstellen, legen wir eine gewöhnliche Liste


mit eckigen Klammern an. Anschließend tragen wir zwischen den Kommata eine
vollständige Liste ein. Dabei ist es sinnvoll, nicht alle Listen in eine Zeile zu schrei-
ben, sondern strukturiert untereinander in mehrere Zeilen. Dabei müssen die
Zeilen eingerückt sein. Spyder erkennt das automatisch und rückt die Zeilen ein.
datensatz4 =[

['Tom', 26,1.84], # Erstes Element

Datenspeicher und Verarbeitung 29


['Lisa',28,1.67], # Zweites Element

['Kevin',34,1.78], # Drittes Element

Ruft man einzelne Werte der Liste ab, wird wie gewohnt das Element
ausgegeben. Diesmal ist das Element eine ganze Liste, sodass auch die
ganze Liste ausgegeben wird.
print(datensatz4[1])

 ['Lisa', 28, 1.67]

Möchte man ein Element einer Unterliste, beispielsweise Kevin abfragen, wird
zunächst der Index der Unterliste und anschließend der Index des Elements an-
gegeben.

In dem Beispiel ist das Element Kevin in der dritten Unterliste (Index 2) und in
der Liste wiederum das erste Element (Index 0).
print(datensatz4[2][0])

 Kevin

Was gibt der Befehl print(datensatz4[0][1]) aus?


Der Index Null steht für die erste Unterliste, davon ist das Element mit
dem Index 1 “26“.

Was gibt der Befehl print(datensatz4[-1][:2]) aus?


Der Index -1 steht für die letzte Unterliste, davon sind die Elemente mit
dem Index Null bis 1 (zwei Elemente)
['Kevin', 34].

Als nächstes lernen wir weitere Methoden kennen, um eine Liste zu erstellen
oder zu bearbeiten.

Die Befehle sind nicht essenziell notwendig und wir können die gleiche Liste auch
händisch erstellen, jedoch sparen wir uns jede Menge Zeit, wenn wir die richtige
Abkürzung kennen.

Erstellen einer Liste mit range()

Die Funktion range(x) erstellt eine Liste mit den Werten Null bis x. Der
Befehl
liste = range(10)

ordnet der Liste die Werte [0,1,2,3,4,5,6,7,8,9] zu.

30 Datenspeicher und Verarbeitung


Dabei muss beachtet werden, dass kein Element mit dem Datentyp list (Liste)
erstellt wird, sondern ein Element des Datentyps range. Im Rahmen dieses Bu-
ches ist das für die Verwendung gleichwertig. Für eine Konsolenausgabe kann
eine Typumwandlung stattfinden, damit die einzelnen Elemente ausgegeben
werden.
liste = range(10) # Typ range

print("Ausgabe als range-Element:",liste)

liste2=list(liste) #Typumwandlung in list

print("Ausgabe als listen-Element:",liste2)

Abbildung 18 range und list im Vergleich

Ein Blick in den Variablen-Explorer bestätigt die Typumwandlung.

Abbildung 19 Variablen-Explorer

Alternativ können der range()-Funktion auch der Start und Endwert angegeben
werden.
Dabei wird der Endwert nicht miterzeugt!
liste = range(3,7)

Gibt die Werte [3,4,5,6] an die Liste weiter. Ohne die Sieben.

Die Funktion range() wird vor allem im nächsten Kapitel (Schleifen und Bedin-
gungen) noch von Bedeutung sein.

4.2. Listen bearbeiten


Mit Listen kann man nicht nur rechnen. Es gibt auch Funktionen, welche das Be-
arbeiten von Listen erheblich vereinfachen.

Datenspeicher und Verarbeitung 31


Da Listen ein sehr weit verbreitetes und einfaches Werkzeug für die Datenspei-
cherung sind, gibt es viele Hilfsmittel zur Vereinfachung der Anwendung, wie
beispielsweise Methoden.

Methoden sind spezielle Funktionen, die nicht für alle Daten verwendet werden
können. Der genaue Unterschied wird im Kapitel Klassen erläutert, da dies für
das jetzige Verständnis und die Anwendung nicht erforderlich ist.

Mit dem Befehl del zum Löschen einer Liste wurde bereits eine Methode einge-
führt, jedoch nicht als solche gekennzeichnet.

Darüber hinaus gibt es viele weitere Methoden zur Bearbeitung einer Liste. Dazu
ist es wichtig, die Methodennamen zu kennen.

Um ein weiteres Element an das Ende einer Liste hinzuzufügen, ist das
mit dem Befehl append() möglich.
liste.append(‚Element‘)

Der Name der Liste wird gefolgt von einem Punkt und dem Methodennamen
aufgerufen.

Das Element, welches der Methode übergeben wird, wird an das Ende der Liste
„liste“ angehängt:
datensatz1 = ['Tom', 26,1.84]

datensatz1.append('Fußball')

Das vierte Element im Beispiel ist Fußball und wird zur Liste „datensatz1“ hinzu-
gefügt.

Darüber hinaus existieren noch weitere Methoden für die Verwendung mit dem
Datentyp Liste.

Beispielsweise können einzelne Elemente gesucht oder gelöscht werden. Für das
Suchen eines Elements wird der Befehl index() verwendet.
listenname.index(‘Element‘)

#sucht ein Element und gibt den Index zurück.

Der Methode wird ein Element, beispielsweise ein Wort, übergeben. Es wird an-
schließend die Liste durchsucht und der Index des passenden Elements als Rück-
gabewert der Methode index() dann ausgegeben.
print(datensatz1.index('Tom'))

gibt den Wert 0 an der Konsole aus, da Tom das Element mit dem Index Null ist.

32 Datenspeicher und Verarbeitung


Die folgende Tabelle zeigt die häufigsten Methoden zur Verwendung in Verbin-
dung mit Listen.

.append() Fügt ein Element am Ende der Liste hinzu.

.clear() Löscht alle Elemente der Liste

.copy() Erzeugt eine Kopie der Liste

.count() Gibt die Anzahl von vorhandenen Einträgen innerhalb der Liste zu-
rück
.extend() Hängt alle Elemente einer zweiten Liste an.

.index() Gibt den Index eines gesuchten Elements zurück.

Wenn nicht vorhanden:

liste1=list(range(10))
liste1.index(11)

ValueError: 11 is not in list


.insert() Fügt ein Element in die Liste ein. Es werden der Index und das Ele-
ment übergeben, zu dem das Element hinzugefügt werden soll. Alle
anderen Elemente verschieben sich um eine Position nach hinten.
.pop() Löscht ein Element aus der Liste. Der Rückgabewert ist der gelöschte
Wert.
.remove() Löscht ein Element aus der Liste.
liste1=list(range(10))

liste1.remove(5)

.sort() Sortiert die Liste den Werten nach, entweder aufsteigend (Zahlen)
oder alphabetisch (strings).
reverse() Spiegelt alle Werte einer Liste, der letzte Wert wird zum ersten, und
umgekehrt.

Weiterhin gibt es Operatoren, die auf Listen angewendet werden können. Wir
können diese Operatoren vergleichen mit den +,-* und / Operatoren, welche wir
auf Zahlen anwenden können.

Die nachfolgende Tabelle zeigt die Aufrufe und Funktion der Operatoren

Datenspeicher und Verarbeitung 33


x in liste Gibt True aus, wenn das Element x in der Liste vorkommt. An-
sonsten False
x not in liste Gibt “False“ aus, wenn das Element x in der Liste vorkommt,
ansonsten “True“.
len(liste) Gibt die Länge (Anzahl der Elemente) der Liste aus.

min(liste) Gibt das kleinste Element zurück.

max(liste) Gibt das größte Element zurück.

sum(liste) Gibt die Summe der Liste zurück.

Listen sind eine einfache und weitverbreite Vorgehensweise, um zusammenhän-


gende, variable Daten zu speichern. Mit Listen kann man leicht rechnen und ver-
schiedene Methoden anwenden. Eine ähnliche Art der Datenspeicherung bilden
Tupel.

4.3. Tupel
Listen enthalten stets variable Daten, was das Arbeiten mit ihnen sehr angenehm
macht, jedoch belegen diese variablen Daten auch zusätzlichen Speicherplatz.
Zudem muss immer mehr Speicherplatz freigehalten werden als zunächst benö-
tigt, falls sich die Variable ändert und größer wird.

Wenn wir jedoch nur unveränderliche Werte haben, verwenden wir anstatt den
Listen sogenannte Tupel. Tupel verhalten sich sehr ähnlich zu Listen. Jedoch kön-
nen die Werte der Elemente nicht verändert werden. Um ein Tupel zu erstellen,
werden die eckigen Klammern der Liste weggelassen. Die Kommata trennen wei-
terhin die Elemente voneinander.
tupel = “Tom“, 26, 1.84

Die Elemente können wie bei Listen durch Nennen des Index abgerufen
werden.
print(tupel[0]) # gibt Tom aus.

Jedoch kann man die Werte nicht überschreiben oder löschen.

Möchte man beispielsweise ein Element mit dem del-Befehl löschen, wird ein
Error ausgegeben, dass die Tupel diesen Befehl nicht unterstützen.
del tupel[2]

34 Datenspeicher und Verarbeitung


Ein Löschen ist nicht möglich.

Allerdings lassen sich weitere Elemente hinzufügen. Dazu wird, wie bei Listen,
das Pluszeichen verwendet.

Zu beachten ist jedoch, dass zu einem Tupel keine Liste oder Wörter, sondern
lediglich eine anderes Tupel addiert werden kann.
tupel1 ='Tom', 26, 1.84

tupel2 = 'männlich', ‘Fußball’

tupel3 = tupel1+tupel2

Wie immer kommt es auf den konkreten Anwendungsfall an, ob Listen oder
Tupel zu bevorzugen sind. Das bringt uns auch zur dritten, sehr ähnlichen Art der
Datenspeicherung, den Dictionaries. Diese sind auch für gewisse Anwendungs-
bereiche extrem nützlich.

4.4. Dictionaries
Nachdem die Handhabung von Listen und Tupeln erläutert wurde, wird nachfol-
gend eine weitere, sehr ähnliche Variante zur Datenstrukturierung behandelt;
die Dictionaries.

Listen sind uns mittlerweile vertraut. Der große Nachteil von Listen ist, dass der
Benutzer wissen muss, wofür welcher Index steht.

Im Beispiel unseres Datensatzes von Tom wurde festgelegt, dass der Index 0 für
den Namen steht, Index 1 für das Alter und Index 2 für die Größe.
datensatz1 = ['Tom',26,1.84]

Es wäre deutlich geschickter, wenn man statt eines Index ein Suchbegriff ange-
ben könnte. Beispielsweise anstatt des Index „Null“ den Suchbegriff name

Unter dieser Problemstellung sind Dictionaries, zu Deutsch Wörterbücher ent-


standen. Sie sind sehr ähnlich aufgebaut wie eine Liste, erfüllen jedoch unsere
Vorgabe und übersetzen den Index in einen Suchbegriff (Key).

Dictionaries beinhalten Schlüsselbegriffe (Keys) und Werte (values). Die


Keys sind in der Regel Zeichenketten.

Als Beispiel legen wir wieder die gleiche Personendatei an. Die keys und values
werden in geschweifte Klammern geschrieben und mittels eines Doppelpunktes
einander zugeordnet. Die Wertepaare werden mit Kommata getrennt.
person1= {'Name':'Tom','Alter':'26','Größe':'1,84'}

Datenspeicher und Verarbeitung 35


Hierbei sind Name, Alter und Größe die Schlüssel und Tom, 26 und 1,84 die
Werte.

Anstatt (wie bei Listen) den Index anzugeben, kann der gewünschte
Wert über den Schlüssel abgerufen werden.
print(person1['Name'])

print(person1['Alter'])

Abbildung 20 Ausgabe der values

Die Verwendung der Dictionaries bietet sich aufgrund des logischen Zusammen-
hangs zwischen den keys und den values an.

Auch gibt es viele Hilfsfunktionen für Dictionaries. Man kann, wie bei Listen, be-
stimmte Elemente löschen, anhängen oder einfügen.

Mit person1.keys() können alle Schlüssel ausgegeben werden.

Mit person1.values() können alle Werte ausgegeben werden.

Mit person1.items() können alle enthaltenen Schlüssel und die dazuge-


hörigen Werte ausgegeben werden.

Abbildung 21 Textausgabe person1.items()

4.5. Schleifen und Bedingungen


Schleifen und Bedingungen sind Hilfswerkzeuge, um ein Programm über-
sichtlicher und effizienter zu steuern. Mit Hilfe von Schleifen kann man
bestimmte Programmabschnitte wiederholen.

Bedingungen können verwendet werden, um Programmteile unter bestimmten


Programmvoraussetzungen zu überspringen oder ausführen lassen. Damit ist
das Programm in der Lage, auf verschiedene Ereignisse mit unterschiedlichen
Reaktionen zu antworten.

36 Datenspeicher und Verarbeitung


Eine der wichtigsten Anweisungen für das Programmieren ist die if-Bedin-
gung. Sie ist in fast allen Programmiersprachen vorhanden und ein we-
sentliches Werkzeug mit vielen Möglichkeiten.

4.6. if-Bedingung
Die „Wenn-dann“ - Anweisung wird nur ausgeführt, wenn eine Bedingung
erfüllt ist. Die Bedingung wird nach dem Signalwort „if“ angeführt. Das
Wort „dann“ wird sozusagen durch einen Doppelpunkt ersetzt.
if x > 4:

Wichtig zu verstehen ist, dass die Bedingung „auf Wahrheit“ geprüft wird. Wer
selbst merkt, dass er hierbei noch Verständnisprobleme beim Interpretieren von
„True/False“ Aussagen hat, sollte nocheinmal die Operator-Tabelle aus dem Ka-
pitel Operatoren anschauen.

Alle Anweisungen, die ausgeführt werden, wenn die Bedingung erfüllt


ist, werden beim Schreiben in der Zeile eingerückt. Das kann durch die
Tabulatortaste oder mehrere Leerzeichen realisiert werden. In jedem
Fall sollte es einheitlich gehalten werden.

Richtig - eingerückt Falsch – nicht eingerückt


if x > 4 : if x > 4 :

print(“Die Zahl ist größer als 4“) print(“Die Zahl ist größer als 4“)

Ist die Bedingung erfüllt, wird der eingerückte Programmcode ausge-


führt.

Ist die Bedingung nicht erfüllt, wird die if-Anweisung übersprungen und
das Programm wird nach dem eingerückten Text fortgesetzt.

Wenn wir alternative Anweisungen integrieren wollen, die ausgeführt werden


sollen, wenn die Bedingung nicht erfüllt ist, verwenden wir den else-Befehl.

Möchten wir nicht nur zwei, sondern mehrere Bedingungen abfragen, funktio-
niert das mit der Erweiterung elif (Abkürzung für else-if). Dabei können wir be-
liebig viele elif-Szenarien einfügen, jedoch immer nur ein if- und ein else-Szena-
rio.

Else und elif sind optional bei einer if-Anweisung:

Datenspeicher und Verarbeitung 37


temp1 = eval(input('Temperatur eingeben')) #Eine Variable wird eingelesen

if temp1==20: #Wenn temp1 den Wert 20 besitzt

print('Die Temperatur beträgt 20 °C')

elif temp1 == 25: #Wenn temp1 den Wert 25 besitzt

print('Die Temperatur beträgt 25 °C')

elif temp1 == 30: #Wenn temp1 den Wert 30 besitzt

print('Die Temperatur beträgt 30 °C')

else: #In allen anderen Fällen

print('Die Temperatur beträgt weder 20, noch 25, noch 30 °C')

Die if-Bedingung kann auch in Verbindung mit einem String eingesetzt werden.
x='hallo'

if x == 'hallo':

print(" Hallo Welt") # wenn die Var. x die Zeichenkette „Hallo“ enthält

else:

print("Tschüss")

Die if-Bedingung benötigt zur Ausführung eine wahre Aussage. Das kön-
nen wir, wie im obigen Beispiel, durch eine Abfrage realisieren. Alterna-
tiv reicht eine Variable, welche bereits einen booleschen Wert
(True/False) besitzt.
x = True

if x:

print(“x ist wahr“)

else:

print(“x ist falsch“)

Im Beispiel ist x auf “True“ gesetzt, daher wird „x ist wahr“ ausgegeben.

Wenn kein Vergleichsoperator verwendet wird, wird jede Zahl ungleich


Null als wahr interpretiert. Lediglich die Null selbst wird als falsch inter-
pretiert.
x = 3 # 3 wird als True interpretiert

if x:

print('x ist wahr')

38 Datenspeicher und Verarbeitung


else:

print('x ist falsch')

 „x ist wahr“

Prüfe selbst: Wann ist die if-Bedingung erfüllt und wann nicht?
If 3 > 5 :

if 3 < 5 :

if 3 :

if 0 :

if not 3 :

if 2==2 :

if (4>2) and (3<1) :

Lösung:
1. Nicht erfüllt. Da 3 kleiner als 5 ist, wird das if-Statement nicht ausgeführt.

2. Erfüllt. 3 ist kleiner als 5, daher wird das if-Statement ausgeführt.

3. Erfüllt. 3 ist eine Zahl ungleich Null, daher wird sie als „wahr“ interpretiert und
das if-Statement wird ausgeführt.

4. Nicht erfüllt. Die Zahl Null wird als „falsch“ interpretiert und das if-Statement
wird nicht ausgeführt.

5. Nicht erfüllt. Die Zahl drei wird als wahr interpretiert, jedoch negiert, daher wird
das if-Statement nicht ausgeführt.

6. Erfüllt, denn 2==2 ist ein wahres Ergebnis.

Achtung, hier muss „==“ zur Prüfung einer wahren Aussage verwen-
det werden. Der Operator „=“ ist eine Zuweisung, keine Prüfung. If
2=2 würde ein Error (invalid syntax) ergeben. Ein häufiger Fehler!

7. Nicht erfüllt. Da sowohl 4 größer als 2 und 3 kleiner als 1 sein müssten, wird das
if-Statement nicht ausgeführt.

4.7. While-Schleife
Schleifen werden benötigt, um Rechenoperationen wiederholt auszuführen. Das
kann zeitlich vorgegeben sein, beispielsweise wenn man alle 15 Minuten die

Datenspeicher und Verarbeitung 39


Raumtemperatur messen möchte, oder auch innerhalb von Bruchteilen einer Se-
kunde, wenn beispielsweise eine künstliche Intelligenz einzelne mathematische
Aufgaben löst.

Die Struktur der while-Schleife ist analog zur if-Bedienung. Die while-Schleife
wird durch den Schlüsselbegriff while eingeleitet. Anschließend wird die Bedin-
gung angegeben. Dahinter wird mit einem Doppelpunkt abgeschlossen.

Die auszuführenden Befehle werden wiederum eingerückt.


while temp1 > 20:
print(“Die Temperatur ist größer als 20 °C“)

Zunächst ist kein Unterschied zur if-Abfrage zu sehen. Jedoch fragt eine if-Ab-
frage nur ein einziges Mal, ob die Bedienung erfüllt ist.

Eine while-Schleife läuft immer weiter, bis die Bedingung “falsch“ wird.
Die Schleife kann auch unendlich laufen, wenn die Bedingung logisch im-
mer erfüllt wird.

Wenn innerhalb der While-Schleife die zu prüfende Bedienung nicht ver-


ändert wird, läuft sie unendlich weiter.

So auch im nachfolgenden Beispiel. Die Variable temp1 wird nicht verändert. Ist
die Variable größer als 20, würde es eine Endlosschleife geben.

Abbildung 22 Endlosschleife, da die Prüfvariable niemals verändert wird

Abhilfe lässt sich zum Beispiel dadurch schaffen, indem die Variable innerhalb
der Schleife verändert werden kann.

40 Datenspeicher und Verarbeitung


while temp1 > 20:

print('Die Temperatur ist größer als 20 °C')

temp1= eval(input('Wie viel Grad sind es momentan?'))

In diesem Beispiel wird der Benutzer innerhalb der Schleife aufgefordert, eine
neue Temperatur einzugeben. Ist die eingegebene Temperatur 20 °C oder gerin-
ger, wird die Schleife bei der nächsten Abfrage nicht mehr durchlaufen. Oftmals
wird in Verbindung mit einer While-Schleife auch eine Zählvariable verwendet.
Dabei handelt es sich um eine Variable, meist i, ii oder j, welche pro Durchlauf
um Eins erhöht wird. Mit Hilfe der Zählvariablen kann die Anzahl der Durchgänge
erfasst werden und eine Abbruch-Bedinung eingeführt werden, beispielsweise
wenn die Zählvariable über einen bestimmten Wert steigt, wird die Schleife ab-
gebrochen.
i =1 # Zählvariable

while i < 10: # Es sollen insgesamt 9 Durchläufe stattfinden (1 -9)

print(“Durchlauf Nummer:“,i)

i=i+1

Abbildung 23 Die Schleife wird 9 Mal durchlaufen

4.8. Die for-Schleife


Prinzipiell kann man eine for-Schleife durch eine while-Schleife ersetzen und
umgekehrt. Je nach Aufgabenstellung ist es jedoch sinnvoll, den passenden
Schleifentyp zu verwenden.

For-Schleifen werden vor allem in Kombination mit Listen und anderen Objek-
ten, welche mehrere Elemente enthalten, verwendet. Dabei wird jedes Element
geprüft. Sobald die for-Schleife keine passenden Elemente mehr finden kann,

Datenspeicher und Verarbeitung 41


wird die Schleife abgebrochen. Der Aufbau ist dabei wieder analog zur if-Abfrage
und zur while-Schleife
automarken = [‘VW‘,‘Audi‘,‘Porsche‘,‘BMW‘ ,‘Skoda‘]

for x in automarken: # Solange ein Element vorhanden ist

print(x) # Wird es ausgegeben

Bei der for-Schleife ist das Signalwort for. Anschließend geben wir eine
beliebige Variable an. Danach folgen das Signalwort in sowie die Liste
bzw. die Sequenz von Elementen.

Solange ein Element vorhanden ist, ist die Bedingung erfüllt. Das Ele-
ment der Liste wird in der Variablen x gespeichert. Im anschließenden
Durchlauf wird das nächste Element geprüft. Die Ausgabe sieht insge-
samt aus wie folgt:

Abbildung 24 Ausgabe aller Listenelemente

Wenn eine Schleife eine bestimmte Anzahl an Durchläufen absolvieren


soll, kann mit Hilfe der Funktion range() eine passende Liste erstellt
werden.
for n in range(10): # 10 Durchläufe mit den Elementen 0 -9

print (n)

Abbildung 25 Ausgabe der Liste range(10)

42 Datenspeicher und Verarbeitung


Die Funktion range(10) erstellt eine Liste von Null bis zur angegeben Zahl
[0,1,2,3,4,5,6,7,8,9]. Die angegebene Zahl wird dabei ausgeschlossen.

Diese Liste wird an die for-Schleife übergeben. Die for-Schleife arbeitet die Ele-
mente ab. Deshalb finden insgesamt 10 Durchläufe (0-9) statt.

4.9. Abbrechen mit break()


Wir haben gelernt, wie man Schleifen und Bedingungen einsetzt und verschie-
dene Fälle abfängt.

Oftmals möchten wir eine Schleife jedoch nicht vollständig ausführen, sondern
vorzeitig abbrechen.

Das einfachste Beispiel bildet dabei ein Suchalgorithmus. Dieser durchläuft eine
Liste, bis er das passende Element gefunden hat.

Danach soll er jedoch nicht weitersuchen, sondern die Schleife abbrechen.

Das Abbrechen einer Schleife, Funktion oder Bedingung kann mit dem
Signalwort break realisiert werden. Sobald dieses innerhalb einer
Schleife auftaucht, wird sie abgebrochen.
automarken = ['VW','Audi','Porsche','BMW','Skoda']

suche = input('Welche Marke soll gesucht werden?')

for n in automarken:

if n == suche: # Wenn das passende Element gefunden wurde

print('Die Marke wurde gefunden')

break # Schleife wird abgebrochen

print(n) #Ansonsten wird die Marke ausgegeben

Zunächst wird die Liste automarken angelegt und der for-Schleife übergeben.
Diese vergleicht das aktuelle Element der Liste mit der gewünschten Eingabe. Bei
einem Treffer (if n == suche) wird die for-Schleife abgebrochen. Ansonsten läuft
sie immer weiter und gibt alle Elemente der Liste aus.

4.10. Übungsaufgabe – Listen und Dictionaries


Die Basics wie Variablen, Operatoren und Listen haben wir behandelt. Auch kön-
nen wir Entscheidungen mit Hilfe von if-Anweisungen treffen. Allgemein ist der
Aufbau der Schleifen in Python sehr einfach gehalten. Jedoch kommt es am An-
fang zwangsläufig zu Fehlern wie Syntax-Fehlern, Zeichenfehlern oder logischen

Datenspeicher und Verarbeitung 43


Fehlern. Darum ist es wichtig, dass wir das Erlernte anwenden und direkt in die
erste kleinere Übungsaufgabe einsteigen.

Alle benötigten Funktionen und Methoden wurden bereits behandelt und kön-
nen bei Bedarf nachgeschlagen werden.

Erste Übungsaufgabe
Der Programmierer soll ein Programm für eine Lagerhalle eines Obstla-
dens erstellen. Für das Beispiel haben wir uns auf lediglich vier Früchte
beschränkt. Das Prinzip bleibt bei 100 Früchten das gleiche. Lediglich
der Programmieraufwand ist höher.

Im Lager gibt es insgesamt vier verschiedene Früchte und die dazuge-


hörigen Lagerbestände, welche in der folgenden Tabelle dargestellt
sind:

Frucht Bestand
Banane 501

Äpfel 112

Mango 52

Kiwi 96

Zunächst sollen die Bestände abgespeichert werden. Dazu empfiehlt sich eine
Liste oder ein Dictionary. Bei einer Liste realisiere die Abfrage mit input()-Funk-
tion und die Auswahl des Bestands über if- und elif- Anweisungen.

Anschließend soll der Benutzer aufgefordert werden, eine der Früchte einzuge-
ben. Das Programm soll dann den passenden Bestand ausgeben.

4.11. Lösung
Wie bei den meisten Programmieraufgaben gibt es auch hier keine Musterlö-
sung. Jeder Programmierer hat seine Vorlieben. Der eine arbeitet lieber mit Lis-
ten, der andere mit Dictionaries. Der eine Programmierer bevorzugt for-schlei-
fen, ein anderer while-Schleifen.

Daher gibt es, neben dem folgenden Code, viele verschiedene Lösungsmöglich-
keiten für die beschriebene Aufgabe. Wenn das Programm mit dem Ausführen
das gewünschte Ergebnis liefert, ist der Code korrekt.

Bei der Eingabe des Obstes muss die jeweilige Bezeichnung in Anfüh-
rungszeichen geschrieben werden, z.B. “Banane“.

44 Datenspeicher und Verarbeitung


'''Übungsaufgabe Lagerbestand‘‘‘

''' MIT LISTEN '''

Bestand = [501,112,52,96] # Liste mit dem Bestand

print("Bitte geben Sie das gewünschte Obst ein")

x=input() # Das gewünschte Obst muss eingegeben werden

if x == "Banane": # Wenn Bananen eingegeben wurde

Index=0 # wird der Index auf Null gesetzt

elif x == "Äpfel":

Index=1

elif x == "Mango":

Index=2

elif x == "Kiwi":

Index=3

Zunächst legen wir die Liste an. Anschließend wird der Benutzer aufgefordert,
die gesuchte Frucht einzugeben. Da die Liste nur mit Indexen arbeitet, muss die
Frucht in den passenden Index umgerechnet werden. Dazu wird eine if-Abfrage
verwendet.

Deutlich einfacher wird die gleiche Aufgabe, wenn man Dictionaries ver-
wendet.
‘‘‘MIT DICTIONARIES'''

Bestand = {'Banane':501,'Äpfel':112,'Mango':52,'Kiwi':96 }

print("Bitte geben Sie das gewünschte Obst ein")

# Die Frucht entspricht dem Index und muss nicht umgerechnet werden

Index=input() # Das gewünschte Obst muss eingegeben werden

Wir können schnell sehen, dass für dieses Beispiel die Verwendung von
Dictionaries einen deutlichen Vorteil bietet. Die Funktion ist dabei die
gleiche.
# Anschließend wird der Bestand ausgegeben

print("Es sind noch",Bestand[Index],"Stück", x, "vorhanden")

bzw. bei der Dictionary Variante:


print("Es sind noch",Bestand[Index],"Stück", Index, "vorhanden") Bei beiden Varian-
ten wird abschließend der Bestand ausge geben.

Datenspeicher und Verarbeitung 45


Der letzte print()-Befehl ist etwas komplexer. Zunächst wird die Zeichenkette
("Es sind noch") ausgegeben.

Anschließend erscheint das Element mit dem Index, welcher zuvor festgelegt
wurde.

Danach wird die zuvor abgefragte Frucht, die in x oder Index gespeichert wurde,
ausgegeben. Als letztes wird die Zeichenkette vorhanden dargestellt. In der
Summe sieht die Ausführung des Programms wie folgt aus:

Abbildung 26 Ausgabe Übung -Listen und Dictionaries

Glückwunsch, wir haben unser erstes Programm geschrieben.


Natürlich es ist sehr minimalistisch. So könnte man es noch nicht an einen Kun-
den verkaufen und bestimmt hat auch nicht alles direkt funktioniert, aber:
Übung macht den Meister!
Selbst erfahrene Programmierer erhalten häufig Fehlermeldungen oder es
funktioniert nicht alles auf Anhieb wie es soll. Mit der Zeit werden die Schreib-
weisen immer vertrauter und man muss die Standardbefehle wie print() oder
input() nicht mehr jedes Mal nachschauen.
Damit kommen wir auch schon zum nächsten großen Themengebiet. Verschie-
dene Standard-Funktionen kennen wir mittlerweile, im folgenden Kapitel wer-
den wir unsere eigenen Funktionen erstellen.

4.12. Funktionen selbst erstellen


Was Funktionen sind und wozu sie dienen, haben wir bereits im Kapitel Funkti-
onen gelernt.

Wir können eine Funktion aufrufen, indem wir ihr ein oder mehrere Argumente
übergeben.

Innerhalb der Funktion werden daraufhin Befehle abgearbeitet und als Resultat
erhalten wir (nicht zwingend) einen oder mehrere Rückgabewerte. Auch wenn
es viele Standardfunktionen bereits gibt, kommt es vor, dass wir eine zuvor noch
nicht erstellte Funktion benötigen. Deshalb ist es sinnvoll und hilfreich, selbst
Funktionen schreiben zu können.

Eigene Funktionen sind nützlich, wenn wir innerhalb eines Programms Pro-
grammteile öfters verwenden.

46 Datenspeicher und Verarbeitung


Eine selbsterstellte Funktion wird in die gleiche Datei wie das Hauptpro-
gramm geschrieben. Das Signalwort ist hierbei def. Darauf folgt der
Name der Funktion.

Bei der Namensgebung gelten die gleichen Regeln wie für die Vergabe von
Variablennamen. Es ist auch hier von Vorteil, einen Namen zu vergeben, welcher
direkt auf den Einsatzzweck der Funktion schließen lässt.

Für die folgenden Abschnitte wird eine Funktion erstellt, welcher eine Zahl x
übergeben wird. Als Rückgabewert soll y=x² ausgegeben werden. Dafür gibt es
in Python den **-Operator, in diesem Beispiel soll der Befehl jedoch mit einer
Funktion realisiert werden. Ein sinnvoller Name für die Funktion wäre beispiels-
weise xsquare (x)
def xsquare(x):

Nach Angabe des Namens der Funktion werden runde Klammern ge-
setzt. In diese kann ein Übergabewert (ein Argument) geschrieben wer-
den.

Bei der xsquare Funktion ist das eine Zahl x. Diese werden wir später im Haupt-
programm anlegen.

Anschließend wird, wie bei der if-Abfrage und Schleifen, ein Doppelpunkt ge-
setzt. Die Befehle müssen auch hier eingerückt werden. Wir sehen, dass es wie-
derkehrende Formatierungsmuster in Python gibt.

Mit der übergebenen Variablen x kann innerhalb des Programms gearbeitet wer-
den. Es können beliebige Befehle ausgeführt werden.
def xsquare(x):

y=x*x

print(x,“-Quadrat ist ”,y)

Der Übergabewert kann auch leer sein, beispielsweise bei der bereits
bekannten Funktion input(). Diese benötigt nicht zwingend einen Über-
gabewert.

Nachdem wir die Funktion erstellt haben, können wir die Funktion aufrufen. Für
das Beispiel wird die Zahl drei übergeben, d.h. die Funktion wird aufgerufen.
def xsquare(x):

y=x*x

print(x,'- Quadrat ist',y)

xsquare(3) # Die Zahl drei wird der Funktion übergeben.

Datenspeicher und Verarbeitung 47


Der Aufruf der Funktion darf dabei nicht mehr eingerückt sein, da diese
Zeile sonst zur Funktion gehört und nicht zum Hauptprogramm. Auch
die Doppelpunkte werden beim Aufruf weggelassen.

def xsquare(x):

y=x*x

print(x,'- Quadrat ist',y)

‘3‘
=> Argument/Übergabewert

xsquare(3 ) Konsolenausgabe

Abbildung 27 Funktionsaufruf xsquare(3)

Als Ausgabe erhalten wir:

Abbildung 28 Ausgabe des Funktionsaufrufs

Als nächstes wollen wir den print()-Befehl im Hauptprogramm ausführen und


nicht mehr innerhalb der Funktion. Dafür wird der print()-Befehl nicht mehr ein-
gerückt. Damit ist er nicht mehr Teil der Funktion.

Außerdem muss er nach dem Funktionsaufruf geschrieben werden.


def xsquare(x):

y=x*x

xsquare(3)

print(x,'- Quadrat ist',y)

Eigentlich sollte die gleiche Ausgabe erfolgen, oder?

Dieser Programmcode gibt jedoch folgende Fehlermeldung aus:

48 Datenspeicher und Verarbeitung


Abbildung 29 Fehlermeldung name 'x' is not defined

Aber warum? Schließlich wird die Variable x doch in der Funktion verwendet.
Dazu müssen wir uns den Unterschied zwischen lokalen und globalen Variablen
anschauen.

Bei der Erstellung von Funktionen ist es wichtig zu verstehen, dass die Variablen
x und y nicht außerhalb des Programms verwendet werden können. Sie sind auf
die Funktion beschränkt und können nur innerhalb dieser verwendet werden.
Man nennt sie daher auch lokale Variablen.

Python unterscheidet, wie viele andere Programmiersprachen auch, zwischen


lokalen Variablen, die innerhalb einer Funktion angelegt werden, und globalen
Variablen, welche im Hauptprogramm verwendbar sind. Das hat beispielsweise
den Vorteil, dass lokale Variablen nach der Verwendung wieder gelöscht werden
können, sodass kein unnötiger Speicher belegt wird.

Eine Funktion bildet quasi eine Blackbox, der ein Wert übergeben werden kann.
Die Werte innerhalb der Blackbox kann man einsehen, aber nicht außerhalb der
Box verwenden.

Wenn man den Wert einer Variablen aus einer Funktion verwenden
möchte, muss dieser mit dem Befehl return zurückgegeben werden.

Zurückgegeben bedeutet, dass der Funktionsaufruf durch den Rückgabewert er-


setzt wird. Als Beispiel kennen wir den input()-Befehl.
input(‘Bitte geben Sie eine Zahl ein‘)

Der Befehl fordert den Benutzer auf einen String einzugeben. Der Rückgabewert
ist dabei der eingegebene String. Möchten wir den Rückgabewert abspeichern,
müssen wir ihn in eine Variable speichern.
eingabe= input(‘Bitte geben Sie eine Zahl ein‘)

Hier ist es wiederum wichtig zu verstehen, dass nur ein Wert zurückgegeben
wird und nicht die lokale Variable selber. Lokal bedeutet, dass wir außerhalb der
Funktion nicht auf sie zugreifen können.

Datenspeicher und Verarbeitung 49


Wenn wir uns an das Box Modell für Variablen erinnern, wird der Inhalt der Va-
riablen zurückgegeben, nicht die Variable selbst.

4 wird zurückgegeben
Funktion

4
y

Abbildung 30 Funktionsrückgabewerte im Box-Modell

Den zurückgegebenen Wert kann man jedoch wieder in einer anderen, globalen
Variablen speichern. Diese kann sowohl im Hauptprogramm, sowie als auch in
den Funktionen verwendet werden.

Für die globale Variable kann sogar der gleiche Name der lokalen Variablen ver-
wendet werden, denn die lokale Variable ist außerhalb der Funktion nicht exis-
tent.

Als Beispiel wenden wir den return-Befehl auf die Funktion xsquare() an:
def xsquare(x):

y = x*x # Lokale Variable y

return y # Der Wert von y wird zurückgegeben

x=3 # x wird definiert

y = xsquare(x) # y wird der Rückgabewert zugewiesen

print(x,'- Quadrat ist',y)

50 Datenspeicher und Verarbeitung


def xsquare(x):

y = x*x

return y

‘3‘ ‘9‘
=> Argument/Übergabewert => Rückgabewert

y = xsquare(3 )
Abbildung 31 Funktion xsquare mit return-Befehl

Wir sehen, dass die lokale Variable y den Wert x*x zugewiesen bekommt, wel-
cher anschließend als Wert von y zurückgegeben wird. Die Variable y kann dabei
nicht außerhalb der Funktion verwendet werden.

Das Beispiel kann noch kompakter geschrieben werden, indem der „Umweg“
über die lokale Variable y ausgelassen wird. Stattdessen wird direkt x*x zurück-
gegeben. In Python wird zunächst der mathematische Ausdruck x*x ausgerech-
net und das Ergebnis zurückgegeben.
def xsquare(x):

return x*x # Es wird x*x gerechnet, dann der Wert zurückgegeben

Wenn eine Funktion mit Hilfe des return-Befehls Werte zurückgibt, wird
die Funktion auch automatisch beendet. Daher muss der return-Befehl
immer der letzte Befehl der Funktion sein.

Es sind auch mehrere return-Befehle möglich, beispielsweise innerhalb einer if-


Anweisung.

Schauen wir uns dafür ein weiteres Beispiel an, bei dem der return-Befehl ver-
wendet wird.

Der folgenden Funktion wird ein Temperaturwert übergeben.


def wetter(temp): # temp wird übergeben

if temp > 30:

return "Es ist zu warm"

elif temp < 15:

Datenspeicher und Verarbeitung 51


return "Es ist zu kalt"

else:

return "Es ist angenehm"

‘‘‘ Hauptprogramm‘‘‘

x= eval(input("Wie viel Grad hat es?")) #Benutzereingabe

y = wetter(x) # Der Rückgabe-String wird in y gespeichert

print(y) # Und anschließend ausgegeben

Wir sehen, dass sich Rückgabewerte nicht nur auf Zahlen beschränken. Auch
Strings sind möglich. Jedoch ist der Rückgabewert dabei abhängig davon, ob die
if-Anweisung erfüllt ist oder nicht.

Je nachdem welcher Fall eintritt, werden unterschiedliche Strings zurückgege-


ben.

4.13. Standard-Argumente setzen


Bisher haben wir Funktionen kennengelernt, welche wir aufrufen können, indem
wir die passenden Argumente übergeben. Im Kapitel Konsolenausgabe mit
print() haben wir eine Leerzeile programmiert, indem wir kein Argument gesetzt
haben.
print() # Gibt eine Leerzeile aus

Dabei wird kein Argument übergeben. Das ist möglich, da die Funktion kein Ar-
gument erwartet oder indem wir innerhalb einer Funktion Standardwerte set-
zen, für den Fall, dass kein Argument angegeben wird. Mit Hilfe von Standard-
werten können eine Funktion und deren Aufruf vereinfacht werden. Komplexe
Funktionen besitzen teilweise mehrere Argumente, welche für Spezialfälle „re-
serviert“ sind. Bei diesen sind viele Standardwerte gesetzt.

Wenn man eine Funktion erzeugt, kann man den Argumenten Standard-
werte zuordnen. Wird beim Funktionsaufruf kein Wert übergeben, wird
der Standardwert übernommen. Wird ein Wert übergeben, wird der
Standardwert überschrieben.

Als Beispiel erweitern wir die Funktion xsquare(), sodass jede Potenz ausgerech-
net werden kann. Die Funktion berechnet folglich den Term

x hoch n 𝑦 = 𝑥 𝑛

Die Funktion benötigt dabei zwei Argumente, die Basis x und den Exponenten n.
def x_hoch_n(x,n):

52 Datenspeicher und Verarbeitung


y = x**n

return y

Als nächstes wollen wir n standardmäßig auf 2 legen, d.h. wenn man nur x über-
gibt, erhält n den Wert 2. Dafür wird beim Definieren der Funktion n=2 gesetzt.
def x_hoch_n(x,n=2):

y = x**n

return y

Wir rufen die Funktion auf, dabei übergeben wir nur einen Wert. Dieser wird in
der Funktion der lokalen Variablen x zugeordnet.

Der Funktionsaufruf
print(x_hoch_n(3)) # x=3 n=2 (Standard)

gibt folglich 9 aus, da 3² = 9

wird hingegen der Wert für n auch übergeben, wird der Standardwert von 2
überschrieben.
print(x_hoch_n(3,3)) # x=3 , n=3

gibt 27 aus, da 33 = 27

Dabei müssen wir darauf achten, dass alle Argumente mit Standardwerten am
Ende der Eingabe stehen.

Warum das so ist, kann man anhand des Beispiels leicht erklären:
def x_hoch_n(x=5,n):

Hier ist x als 5 gesetzt. Jetzt wäre anzunehmen, dass, wenn wir nur eine Zahl
übergeben, die Zahl automatisch der Variablen n zugeordnet wird. Das ist jedoch
nicht immer der Fall.

Der Aufruf
print(x_hoch_n(3)) # x =3 , n = undefiniert

überschreibt die Variable x auf 3, da diese vor dem n steht.

Da im Anschluss kein weiterer Wert für n festgelegt wurde, erscheint eine Feh-
lermeldung, dass zu wenige Argumente übergeben worden sind.
SyntaxError: non-default argument follows default argument.

‘Argument ohne Standardwert folgt einem Argument mit Standardwert‘

Datenspeicher und Verarbeitung 53


Um das zu vermeiden, wird dieser Fehler automatisch erkannt und die Fehler-
meldung erscheint bereits vor dem Ausführen der Funktion.

4.14. Funktionen in Modulen auslagern


Wir wissen bereits, wie man Funktionen anwendet und sogar wie man Funktio-
nen selbst programmiert. Diesen Funktionen übergeben wir ein oder mehrere
Argumente und erhalten ggf. einen oder mehrere Rückgabewerte.

Die behandelten Funktionen waren dabei relativ simpel aufgebaut. Die Funktion
xsquare() besteht lediglich aus einigen Zeilen.

Komplexere Funktionen können hingegen deutlich mehr Code-Zeilen in An-


spruch nehmen. Außerdem können bei größeren Programmen schnell dutzende
bis hunderte von Funktionen verwendet werden. Daher macht es Sinn, das An-
legen der Funktionen in einer eigenen Datei abzuspeichern.

Im Hauptprogramm tauchen diese nur noch auf, wenn man sie aufruft. Dieses
Vorgehen optimiert die Übersicht und Struktur des Programms.

Außerdem kann ein Programmierer seine eigens erstellten Funktionen an andere


Programmierer weitergeben, ohne dass diese das gesamte Hauptprogramm er-
halten müssen. Ein Beispiel ist die Funktion print(). Ihr Programmcode ist bisher
noch nirgends erschienen, trotzdem verwenden wir sie ohne Probleme.

Um selbst eine Funktion auszulagern, legen wir eine neue Datei an, in die wir alle
Funktionen schreiben, welche wir auslagern wollen. Diese wird als modul_xsqu-
are.py abgespeichert.

Eine Datei, welche ausgelagerte Funktionen enthält, wird als Modul be-
zeichnet.

Als Beispiel für ein Modul wird die xsquare()-Funktion in die Datei modul_xsqu-
are.py geschrieben.

Abbildung 32 Die Funktion wurde in ein Modul ausgelagert

Im Beispiel enthält das Modul lediglich eine Funktion. Für gewöhnlich sind meh-
rere Funktionen in einem Modul zusammengefasst.

54 Datenspeicher und Verarbeitung


Als nächstes wird das Hauptprogramm erstellt. Dieses könnte wie folgt ausse-
hen:
x = eval(input("Geben Sie eine Zahl ein")) # x wird definiert

y = xsquare(x) # y wird der Rückgabewert zugewiesen

print(x,'- Quadrat ist',y)

Das Programm fordert den Nutzer auf, eine Zahl einzugeben. Anschließend wird
die Funktion xsquare() aufgerufen, welche das Quadrat der eingegebenen Zahl
zurückgibt. Die Zahl und das Quadrat werden für die Konsole ausgegeben. Bevor
wir das Modul nutzen zu können, müssen wir es mit dem Signalwort import im-
portieren. Die Endung .py der Datei wird dabei weggelassen.
import modul_xsquare

Das Modul wurde importiert, jedoch kann die Funktion xsquare() nicht ohne An-
passung genutzt werden. Um die Funktion aus dem Modul verwenden zu kön-
nen, wird beim Aufruf der Funktion zunächst die Modulbezeichnung, dann ein
Punkt und anschließend der Funktionsname geschrieben.
import modul_xsquare

x = eval(input("Geben Sie e ine Zahl ein")) # x wird definiert

y =modul_xsquare.xsquare(x)

print(x,'- Quadrat ist',y)

Dabei muss sichergestellt werden, dass das Modul und das Hauptpro-
gramm im gleichen Ordner liegen.

Alternativ kann ein Unterordner angelegt werden. Dann muss beim Importieren
des Moduls zusätzlich der Pfad des Unterordner vorangestellt werden. Das gleich
gilt für den Funktionsaufruf, auch hier muss der Pfad des Unterordners vorange-
stellt werden.

Liegt die Datei modul_xsquare im Unterordner module, dann wird der


Unterordner mit einem Punkt als Trennzeichen vor das Modul geschrie-
ben.
import module.modul_xsquare

y= module.modul_xsquare.xsquare(x)

Abhängig von dem Speicherort der Funktion müssen wir ein Modul und ggf. ei-
nen Unterordner angeben.

Datenspeicher und Verarbeitung 55


y = xsquare(x) Wenn die Funktion im glei-
chen Programm aufgeführt
ist
import modul_xsquare Wenn die Funktion in der
y =modul_xsquare.xsquare(x) Datei modul_xsqare im sel-
ben Ordner liegt
import module.modul_xsquare Wenn die Datei mo-
y= module.modul_xsquare.xsquare(x) dul_xsquare im Unterord-
ner module liegt

Es ist offensichtlich, dass vor allem die dritte Variante schnell unübersichtlich
wird. Die Bezeichnung des abgespeicherten Moduls modul_xsquare ist nicht vor-
teilhaft gewählt. Bei jedem Funktionsaufruf muss der Modulname vorange-
schrieben werden. Dadurch werden die Funktionsaufrufe lang und unübersicht-
lich.

Alternativ kann ein Modul einmalig in das Hauptprogramm importiert werden,


um anschließend einer Funktion im Hauptprogramm eine Funktion des Moduls
zuzuweisen. Dafür wird der gleiche Name wie die Funktion verwendet.
Funktion = Unterordner.Modul.Funktion_aus_dem_Moduls

Für das Beispiel sieht das wie folgt aus:


import module.modul_xsquare

xsquare = module.modul_xsquare.xsquare

Anschließend kann im Hauptprogramm die neu angelegte Funktion xsqu-


are()welche der Funktion xsquare() aus dem Modul modul_xsquare gleicht ver-
wendet werden, ohne jedes Mal den gesamten Pfadnamen angeben zu müssen.
import module.modul_xsquare

xsquare = module.modul_xsquare.xsquare

x=eval(input("Geben Sie eine Zahl ein"))

y= xsquare(x) # Es muss kein Pfad angegeben werden

print(x,'- Quadrat ist',y)

Der Vorteil dieser Vorgehensweise besteht darin, dass man nicht jedes Mal den
gesamten Modul-Pfad angeben muss. Jedoch wird beim Programmieren der Ur-
sprung der Funktion leicht übersehen, da aus dem Aufbau nicht mehr erkennbar
ist, dass sie aus einem Modul importiert wurde.

56 Datenspeicher und Verarbeitung


Eine weitere Methode, welche einen Kompromiss zwischen Umfang und Über-
sicht bietet, ist, den Modulnamen beim Importieren abzukürzen.

Wenn ein oder mehrere Module importiert werden, kann man ihnen
eine Abkürzung zuweisen. Das geschieht durch Hinzufügen der Bezeich-
nung „as“ nach dem Modulnamen sowie der gewählten Abkürzung.
Diese Angabe kann dabei frei gewählt werden. Auch hier dienen wieder
Punkte als Trennzeichen.
import modul_xsquare as xsq

Fortan muss bei einem Funktionsaufruf nicht mehr der vollständige Modulname
inklusive Pfad angegeben werden, sondern lediglich die Abkürzung.
y= xsq.xsquare(x) # Es muss kein Pfad angegeben werden

Es wurde bereits angesprochen, dass ein Vorteil von Modulen darin liegt, dass
man sie unabhängig vom Hauptprogramm weitergeben kann.

Daher ist es sinnvoll, bereits erstellte Module auch zu nutzen, und diese nicht
selbst zu schreiben.

Hier wird wieder ein Vorteil von Python deutlich. Es gibt eine enorme Commu-
nity rund um diese Programmiersprache. Deshalb sind sehr viele Standardmo-
dule und Funktionen bereits programmiert worden und stehen für alle zur freien
Verfügung.

Wenn mehrere Module gebündelt werden, spricht man auch von einer Biblio-
thek.

4.15. Bibliotheken
Bibliotheken (engl. libraries) sind ein Vorteil des open-source-Konzeptes, das Py-
thon verfolgt.

Es existieren viele Standard-Bibliotheken, die die Programmierung mit


Python erleichtern. Vor allem für Einsteiger bietet es sich an, beste-
hende Bibliotheken zu verwenden.

Dafür müssen wir jedoch genau wissen, wie man die richtigen Funktionen findet
und wie man sie korrekt implementiert.

Hinter einer Bibliothek verbergen sich meistens umfangreiche Codes, deren Ver-
ständnis jedoch zur Benutzung nicht erforderlich ist. Funktionen wie input() oder
print() können verwendet werden, ohne dass das dazugehörige Modul impor-
tiert wurde, da es sich hierbei um sogenannte Built-in-Funktionen handelt.
Diese werden so häufig verwendet, dass sie direkt in den Interpreter eingebaut

Datenspeicher und Verarbeitung 57


sind. Unter https://docs.python.org/3/library/functions.html sind die Built-in-
Funktionen aufgeführt und erklärt.

Übersetzung:
Der Python-Interpreter besitzt Funktionen und Typen, welche standardmäßig inkludiert und damit
immer verfügbar sind. Sie sind in der folgenden Tabelle alphabetisch aufgelistet.

Abbildung 33 Übersicht aller Built-in-Funktionen

Wir finden hier auch die bekannten Funktionen wie input(), eval(), print() oder
range() wieder.

Die Standardbibliotheken von Python bestehen zum größten Teil auch aus nor-
malen Modulen, wie sie im vorherigen Kapitel erklärt wurden. Wenn möglich
sollte man immer auf diese Bibliotheken zurückgreifen, da sich dadurch viel Ar-
beit ersparen lässt.

Neben den Built-in-Bibliotheken verwendet Python auch Built-in-Konstanten


wie True/False oder Built-in-Typen wie Listen und Dictionaries.

Diese Built-in-Elemente vereinfachen die Programmierung sowie den


Einstieg in Python auch für Neulinge.

Die Standardbibliotheken bzw. die enthaltenen Funktionen sind unter

58 Datenspeicher und Verarbeitung


https://docs.python.org/3/library/index.html zu finden. Es empfiehlt sich, bei
einem Projekt immer erst nachzuschlagen, ob bereits eine passende Funktion
oder ganze Module vorhanden sind.

Alternativ findet man durch die Suchfunktion innerhalb der Python-Seite oder
über die Suchmaschinen meistens innerhalb kurzer Zeit die passende Funktion
für das Projekt.

4.16. Übungsaufgabe – Durchschnittnote berechnen


In der nächsten Übung wollen wir den Umgang mit Funktionen festigen. Dazu
soll eine eigene Funktion erstellt und im Hauptprogramm miteinbezogen wer-
den.

Das folgende Programm soll die Durchschnittsnote eines Schülers berechnen


und ausgeben.
Die Durchschnittsnote setzt sich zusammen aus den einzelnen Fächern geteilt
durch die Anzahl der Fächer.
Wir gehen von einem vereinfachten Fall mit lediglich drei Hauptfächern aus
(Mathe, Deutsch, Englisch). Die Note ergibt sich in diesem Fall aus:

NMa + NDe + NEng


Note∅ =
3
Die einzelnen Noten der Fächer müssen dabei zunächst errechnet werden.
Für jedes Fach liegen eine mündliche Note sowie eine schriftliche Note vor,
welche doppelt gewichtet wird. Somit lässt sich beispielsweise die Mathenote
folgendermaßen berechnen:

NMa−münd + 2 · NMa−schrift
NMa =
3

Die Noten für die Übung sind bereits in der folgenden Tabelle aufgeführt.
Mathe_s entspricht dabei der schriftlichen Mathenote, Mathe_m der Mündli-
chen

Fach Mathe_s Mathe_m Deutsch_s Deutsch_m Englisch_s Englisch_m


Note 1,3 2,0 2,5 2,0 3,0 2,5

Unsere Aufgabenstellung für die Übungsaufgabe ist dabei:

- Speicher die Noten in einer Liste oder einem Dictionary ab.

Datenspeicher und Verarbeitung 59


- Erstelle eine Funktion, welche jeweils die Durchschnittsnote eines
Fachs berechnet.

- Erstelle anschließend eine Funktion, welche jeweils die Durchschnitts-


note des Schülers berechnet.

- Übergebe den Funktionen die Noten der einzelnen Fächer, sodass die
Noten der Fächer sowie die Gesamtnote zurückgegeben werden.

- Gib sowohl die Noten der Fächer als auch die Gesamtnote aus.

- Zusatz: Speicher die Funktionen in einer eigenen Datei und beziehe


diese über einen import-Befehl mit ein.

4.17. Lösung
Wie immer gibt es mehrere Lösungsansätze. Das folgende Programm zeigt ledig-
lich einen möglichen Weg.

Zunächst speichern wir die Noten aus der Tabelle in einem Dictionary ab. Die
Schlüssel (keys) des Dictionaries sind dabei die Bezeichnungen der Fächer.
noten = {'ma_s':1.3,'ma_m':2,

'de_s':2.5,'de_m':2,

'en_s':3,'en_m':2.5

Anschließend erstellen wir eine Funktion, welche jeweils die Durchschnittsnote


eines Faches berechnet und zurückgibt.
def noteFach(schrift,münd):

return (2*schrift+münd)/3

Der Funktion werden zwei Werte übergeben. Der Rückgabewert ist die Durch-
schnittsnote des Fachs.

Möchten wir beispielsweise die Mathenote ermitteln, rufen wir die Funktion
noteFach() auf und übergeben die entsprechenden Noten aus dem Dictionary.
Um den Wert der schriftlichen Mathenote (1,3) zu erhalten, wird der Schlüssel
angegeben
noten['ma_s']

Analog wird der Wert noten['ma_m'] für die mündliche Mathenote (2,0) aufge-
rufen.

60 Datenspeicher und Verarbeitung


ma_ges= noteFach(noten['ma_s'],noten['ma_m'])

Es ist sinnvoll, die Note auf maximal zwei Nachkommastellen zu runden. Der
Funktionsaufruf wird dadurch erweitert zu:
ma_ges=round(noteFach(noten['ma_s'],Noten['ma_m']),2)

Analog rufen wir die Funktion für alle Fächer auf.


de_ges=round(noteFach(noten['de_s'],noten['de_m']),2)

en_ges=round(noteFach(noten['en_s'],noten['en_m']),2)

Damit haben wir die drei Noten der Fächer in den Variablen ma_ges, de_ges
und en_ges abgespeichert.
Anschließend kann die Funktion für die Bestimmung der Durchschnittsnote der
drei Fächer erstellt werden.
Die Funktion erhält den Namen noteGes() und ihr werden allgemein drei Fächer
übergeben.
def noteGes(fach1,fach2,fach3):

return (fach1+fach2+fach3)/3

Nach der Definition wird die Funktion aufgerufen. Dafür übergeben wir ihr die
drei zuvor errechneten Durchschnittsnoten der Fächer. Gleichzeitig runden wir
die Note wieder auf zwei Nachkommastellen.
n_ges=round(noteGes(ma_ges,de_ges,en_ges),2)

Als letztes geben wir alle Werte an der Konsole aus.


print("Die Gesamtnote in Mathe ist:",ma_ges)

print("Die Gesamtnote in Deutsch ist:",de_ges)

print("Die Gesamtnote in Englisch ist:",en_ges)

print("Die Gesamtnote ist:",n_ges)

Zusatz:
Die beiden Funktionen noteFach() und noteGes() werden in ein Modul mit dem
Namen modul_noten.py gespeichert. Die Datei liegt im gleichen Ordner wie das
Hauptprogramm.
Um die Funktionen wieder nutzen zu können, müssen wir das Modul
im Hauptprogramm importieren.
import modul_noten

Anschließend müssen die wir noch die Funktionsaufrufe anpassen. Vor


jede Funktion wird das Modul geschrieben.
ma_ges= modul_noten.noteFach(noten['ma_s'],Noten['ma_m'])

Datenspeicher und Verarbeitung 61


Wir erinnern uns, dass es eine bessere Alternative gibt, als bei jedem Funkti-
onsaufruf den ganzen Pfad anzugeben. Stattdessen ordnen wir die Funktion
nach dem Importieren neu zu.
import modul_noten

noteFach = modul_noten.noteFach

noteGes = modul_noten.noteGes

Damit ersparen wir uns bei jedem Funktionsaufruf das Angeben des Moduls.
Mit diesem Code wurde die Aufgabe gelöst und mit Hilfe der Tricks, welcher wir
uns bedienen, umfasst er nur wenige Zeilen.
Bei diesem Programm hält sich der Aufwand noch in Grenzen, allerdings kann
es bei komplexeren Aufgaben schnell unübersichtlich werden.
Daher empfiehlt es sich, sich die hier beschriebene Vorgehensweise von Anfang
an anzugewöhnen. Im nächsten Kapitel lernen wir ein Kernelement der Python-
Programmierung kennen, das objektorientierte Programmieren.

62 Datenspeicher und Verarbeitung


5. Objektorientieres Programmieren OOP
Wir haben bereits alle wichtigen Grundbausteine sowie die Datenspeicherung
und Datenverarbeitung kennengelernt. In diesem Kapitel befassen wir uns mit
einer Technik, mit der wir Gegenstände aus dem echten Leben in einen Pro-
gramm-Code überführen können. Dafür schauen wir uns zunächst die Klassifi-
zierung von Gegenständen an.

5.1. Klassen
Die Einteilung von Objekten aus der realen Welt in Klassen hilft unserem Gehirn,
effektiver zu arbeiten. Innerhalb von Bruchteilen einer Sekunde erkennt es Ge-
meinsamkeiten und Unterschiede.

Klassen werden verwendet um Gegenstände oder Personen (Objekte)


mit mehreren Eigenschaften zu beschreiben.

Eine Klasse ist ein abstrakter Begriff, welcher die Gemeinsamkeiten im Verhalten
von Objekten beschreibt. Man spricht dabei von Klassifizierung. Als Beispiel neh-
men wir die Klasse Mensch.

Die Klasse Mensch kann beispielsweise mit den Attributen Name, Alter, Größe
etc. definiert sein und verschiedene Verhaltensweisen (Sprechen, Arbeiten,
Schlafen etc.) zeigen. Jeder individuelle Mensch ist dabei ein Objekt der Klasse.

Aus diesem Grund bezeichnet man das Programmieren mit Klassen


auch als objektorientierte Programmierung, kurz OOP. Ein Objekt be-
schreibt dabei die Abbildung eines realen Gegenstands (dem Men-
schen) aus der „realen Welt“.

Mit Hilfe der Klasse kann man beliebig viele Objekte (Menschen) erzeugen, wel-
che alle die gleichen Attribute besitzen.

Objektorientieres Programmieren OOP 63


Mensch1

Tom
26
1.84

Sprechen
Arbeiten
Schlafen

Mensch2
Klasse: Mensch Lisa
28
Attribute: 1,67
Name
Alter Sprechen
Größe Arbeiten
Schlafen
Verhaltensweisen
Sprechen
Arbeiten
Mensch3
Schlafen
Kevin
34
1,87

Sprechen
Arbeiten
Schlafen

Man beschränkt sich beim Erstellen einer Klasse auf die wesentlichen Merkmale,
welche dem Zweck dienlich sind. Diese sind je nach Aufgabe und Themenstellung
unterschiedlich.

Schauen wir uns an, wie man eine Klasse in Python erstellt und verwendet.

Vom Aufbau her erinnert eine Klasse an eine Mischung aus Funktionen und Dic-
tionaries. Zunächst wird das Signalwort class angeführt, danach der Name der
Klasse, gefolgt von einem Doppelpunkt.
class Mensch:

Anders als bei Funktionen benötigt die Klasse (noch) keine Übergabewerte. Dem-
entsprechend fallen auch die runden Klammern, wie wir sie von Funktionen ken-
nen, weg.

Es ist üblich, Klassenbezeichnungen mit einem großen Buchstaben zu


beginnen, um sie von Variablen und Funktionen unterscheiden zu kön-
nen.

64 Objektorientieres Programmieren OOP


Die folgenden Codezeilen werden eingerückt. Wie bei Funktionen und Schleifen
zeigt das, dass der Code zum Gerüst class gehört.

Als nächstes wird eine Funktion eingeführt, mit der ein Objekt initialisiert (er-
zeugt) werden kann. Dafür wird ein so genannter Konstruktor verwendet.

Ein Konstruktor ist eine Funktion zur Erstellung eines „Gerüsts“ für ein
Objekt. Er kann die Eigenschaft (Attribut) eines Objekts definieren,
ohne dass ihr ein Wert zugewiesen werden muss.

Für das Beispiel bedeutet das, dass man mit dem Konstruktor beispielsweise die
Eigenschaft Name festlegen kann, ohne einen konkreten Namen zu ergänzen.
Ohne diese Funktion müsste man einen festen Namen vergeben, welcher für je-
des Objekt der Klasse gilt. Würde man namen = Tom festlegen, würde jedes er-
zeugte Objekt automatisch den Namen Tom erhalten. Das wollen wir natürlich
nicht. Mit Hilfe des Konstruktors umgehen wir diesen Sachverhalt. Deshalb ver-
wenden wir bei jeder Klasse einen Konstruktor.

Da der Konstruktor eine Funktion ist, wird er mit def eingeleitet. Anschließend
folgt der Ausdruck __init__().

Achtung: Es sind jeweils zwei Unterstriche vor und nach init zu setzen.

Danach können der Funktion Werte übergeben werden, welche in runden Klam-
mern stehen. Eine Besonderheit dabei ist, dass der erste Übergabewert des Kon-
struktors der Ausdruck self sein muss. Der Ausdruck wird in der Benutzerober-
fläche Spyder automatisch erkannt und rot angezeigt.

self gibt dem Konstruktor vor, dass ein Objekt der eigenen Klasse über-
geben wird.

Anschließend können weitere Werte zugeordnet und innerhalb der Funktion


(des Konstruktors) verwendet werden.

Innerhalb des Konstruktors legen wir die Attribute der Klasse fest, im vorliegen-
den Fall den Namen, das Alter und die Größe. Für jedes Element einer Klasse
muss die Bezeichnung self. vorangestellt werden.

Das zeigt dem Konstruktor, dass der Inhalt einer Objektvariablen zugeordnet
wird.

Die Programmierung ist anfangs gewöhnungsbedürftig, daher gehen wir das Er-
stellen einer Klasse anhand der Klasse Mensch durch.

In Beispiel Mensch sieht die Erstellung der Klasse und des Konstruktors wie folgt
aus:

Objektorientieres Programmieren OOP 65


class Mensch:

def _init_(self,name,alter,größe,):

self.Name=name #Speichern der übergebenen Variablen

self.Alter=alter

self.größe=größe

Für eine bessere Übersichtlichkeit empfiehlt es sich, auch innerhalb ei-


ner Klasse, genau wie bei der Beschreibung eines Programms, eine Be-
schreibung des Nutzens der Klasse als Docstring einzufügen.

Diese Beschreibung macht es dem Programmierer leichter, die Hintergründe und


den Nutzen der Klasse zu verstehen.

Eine sinnvolle Beschreibung für das Beispiel wäre:


'''Übung Klassen und Vererbung'''

class Mensch:

'''Erstellung des Objekts Mensch'''

def _init_(self,name,alter,größe,):

'''Die Argumente des Menschen werden definiert

(string) Name: Name des Menschen

(int) alter: Alter des Menschen

(float) Größe: Größe des Menschen

'''

self.Name=name #Speichern der übergebenen Variablen

self.Alter=alter

self.größe=größe

Damit ist eine Klasse angelegt.

Es ist sinnvoll, die Datentypen der Attribute und deren Funktion aufzuführen.

Wir haben jetzt zwar das Grundgerüst, jedoch noch kein Objekt angelegt. Mit
Hilfe der Klassen ist das jedoch sehr einfach. Dazu wird wieder ein individueller
Name angelegt. In unserem Beispiel erstellen wir Tom, welcher als Objekt
mensch1 bezeichnet wird.

Das Objekt mensch1 wird erzeugt, indem man die Klasse angibt und der Klasse
die Attribute des Konstruktors übergibt. Intern wird jetzt die -Konstruktor-Funk-
tion ausgeführt, die Attribute werden zugewiesen und das Objekt wird erstellt.

Jedes erzeugte Objekt besitzt alle Attribute der Klasse.

66 Objektorientieres Programmieren OOP


Die Schreibweise ist dabei
Objekt = Klasse(Attribut1,Attribut2,…)

Beispiel für unsere Klasse Mensch :


mensch1=Mensch("Tom", 26, 1.84)

Somit wurde das erste Objekt der Klasse Mensch erstellt. Die einzelnen Attribute
des Objekts können wir durch Nennen des Objekts und der gewünschten Eigen-
schaft auslesen.
print(mensch1.Name)

print(mensch1.Alter)

print(mensch1.Größe)

 Tom

 26

 1.84

Einzelne Werte des Objekts können auch nachträglich eingetragen oder über-
schrieben werden.
mensch1.Name="Tim"

In dem Beispiel wurde der Name von Tom in Tim geändert. Programmtechnisch
ist das kein Problem, logisch gesehen jedoch schon. Denn die Umbenennung ei-
nes Menschen ist (außer in Einzelfällen) nicht sinnvoll. Da ein Objekt einen realen
Gegenstand abbildet, müssen wir diese Problemstellung angehen.

Python bietet auch hierfür eine Methode, um bestimmte Attribute einer Klasse
zu schützen. Dafür schauen wir uns die Unterteilung von Attributen in public,
protected und private an.

5.2. Kapselung von Klassen -public, protected, private


Für einzelne Elemente einer Klasse ist es sinnvoll, diese zu schützen. Beispiels-
weise soll man den Namen einer Person nicht überschreiben oder ein Passwort
nicht einfach auslesen können. Denn wir können jede Art von Attribut erstel-
len; Passwörter, persönliche Daten oder firmeninterne Inhalte. Das Öffnet Tü-
ren für böswillige Angreifer. Wenn beispielsweise eine Bank die Kontodaten
nicht schützt könnten Angreifer mit Leichtigkeit Kontostände überschreiben.
Wir müssen die Attribute vor der Außenwelt schützen, sodass ein Zugriff auf
diese Elemente nicht mehr möglich ist. Die Außenwelt ist dabei das Hauptpro-
gramm oder andere Klassen.

Objektorientieres Programmieren OOP 67


Das ist vor allem aus sicherheitstechnischen Aspekten sinnvoll, damit sensible
Daten nicht durch einen einfachen Befehl ausgelesen werden können.

Um Variablen vor der Außenwelt zu schützen, kann man diese auf „öf-
fentlich“ (public), „geschützt“ (protected), oder „privat“ (private) set-
zen.

Aber wie setzen wir das korrekt um? Die bisherige Definition von Attributen, in
der nur der Variablennamen angeführt wird, zeigt eine öffentliche Eigenschaft
des Objekts.
self.Name=name # dieses Attribut ist frei zugänglich/public

Das Attribut kann auch außerhalb der Klasse verwendet werden.

Setzt man jedoch einen Unterstrich vor die Variable, ist sie geschützt und kann
nur innerhalb der eigenen Klasse und in Unterklassen (siehe nächstes Kapitel)
verwendet werden.

Eine private Variable wird mit zwei Unterstrichen gekennzeichnet und steht nur
in der eigenen Klasse zur Verfügung. Bei beiden Fällen spricht man von Kapse-
lung.

self.Name=name Public – kann öffentlich gelesen


und geschrieben werden
self._Name=name Protect – kann in der Klasse und
in Unterklassen verwendet wer-
den
self.__Name=name Private – kann nur in der eigenen
Klasse verwendet werden

68 Objektorientieres Programmieren OOP


Klasse: Mensch

Public
Name
Alter
Größe Kein direkter Zugriff

Privat/protect
Außenwelt
z.B. Passwort

Verhaltensweisen
sprechen
arbeiten
schlafen

Abbildung 34 Kapselung von Attributen

Wie die Abbildung zeigt ist kein direkter Zugriff auf die Attribute möglich. Jedoch
kann dennoch über Umwege auf die Attribute zugegriffen werden, beispiels-
weise über Verhaltensweisen. Das ist auch gewollt. Lediglich der direkte, unkon-
trollierbare Zugriff soll verhindert werden. Innerhalb einer Verhaltensweise kann
das Passwort verwendet werden. Eine Verhaltensweise, in der das der Fall ist,
wäre z.B. „In Online-Banking einloggen“.

Die Kapselung erzeugt jedoch auch Probleme. Der Name kann nun nicht mehr
überschrieben werden, jedoch kann man ihn auch nicht mehr auslesen.

Der Befehl
print(mensch1.Name) #gibt (eigentlich) den Namen aus

gibt einen Error aus.

Im Beispiel ist es nicht sinnvoll, den Namen zu ändern, jedoch ist auch kein Zu-
griff mehr möglich, sodass er auch nicht für andere Zwecke ausgegeben oder
ausgelesen werden kann. Man hat zwar an Sicherheit gewonnen, jedoch an
Funktionalität verloren. Das war nicht der Ursprungsgedanke, warum wir Vari-
ablen gekapselt haben.

Wie immer gibt es auch hier eine Lösung in Python.

Man kann innerhalb einer Klasse sogenannte Methoden einführen. Mit Metho-
den können auch gekapselte Attribute bearbeitet oder ausgegeben werden, wie
wir im folgenden Unterkapitel erfahren.

Objektorientieres Programmieren OOP 69


5.3. Methoden
Methoden sind den Funktionen vom Aufbau her sehr ähnlich. Jedoch sind Me-
thoden innerhalb einer Klasse definiert und auch an diese gebunden. Das bedeu-
tet, dass man eine Methode nicht außerhalb der Klasse, beispielsweise im Haupt-
programm, mit anderen Variablen verwenden kann. Methoden können nur mit
einem Objekt der Klasse aufgerufen werden. Der Konstruktor __init__() war un-
sere erste Methode, die wir kennengelernt haben.

Da es sich um eine interne Funktion handelt, wird die Methode mit dem Sig-
nalwort def angelegt. Anschließend vergeben wir einen individuellen Namen der
Funktion. In unserem Fall soll die Klasse Mensch die Methode grüßen erhalten.
Der Methode können wieder in runden Klammern Argumente übergeben wer-
den.

Auch hier muss ebenfalls das Signalwort self als erster Wert übergeben werden.
Das zeigt dem Interpreter, dass es sich hierbei um eine interne Funktion, eine
Methode, handelt.
def grüßen(self):

print('Hallo, ich heiße',self.Name)

Die Methode gibt das Attribut self.Name des Objekts aus.

Obwohl das Attribut selbst geschützt ist, kann man es innerhalb einer Methode
verwenden und ausgeben lassen.

Aufgerufen wird die Methode im Hauptprogramm wie eine normale Funktion.


Da es sich um eine klassengebundene Funktion handelt, muss auch hier das Ob-
jekt mensch1 vorangestellt werden.
class Mensch:

'''Erstellung des Objekts Mensch'''

def __init__(self, name, alter, größe):

'''Die Argumente des Menschen werden definiert

(string) Name: Name des Menschen

(int) alter: Alter des Menschen

(float) Größe: Größe des Menschen

'''

self.__Name=name #Speichern der übergebenen Variablen

self.__Alter=alter

self.__Größe=größe

70 Objektorientieres Programmieren OOP


def grüßen(self):

print('Hallo, ich heisse',self. __Name)

mensch1=Mensch("Tom", 26, 1.84)

mensch1.grüßen()

Methoden sind weiterhin nützlich, um einem Objekte einer Klasse weitere Fä-
higkeiten zuzuordnen. Damit können Objekt mit dem Benutzer oder anderen Ob-
jekten kommunizieren.

Methoden können dabei wie Funktionen auch, selbst erstellt werden. In den
meisten Klassen werden Standardmethoden angelegt, um geschützte Attribute
zu ändern oder auszulesen. Deshalb lohnt es sich, diese genauer zu betrachten.

5.4. Set und Get - Methoden


Diese Methoden bieten sich oft an, wenn man Attribute in einer Klasse auslesen
oder setzen kann. Dafür wird eine Methode angelegt, welche ein Attribut verän-
dert (set) oder den Wert ausgibt (get). Der Name der Methode kann frei gewählt
werden. Es ist jedoch internationaler Standard, die Methoden mit den Wörtern
get oder set zu beginnen. Eine Methode, welche das Alter der Klasse Mensch
ausgibt, sollte getAlter genannt werden.
def getAlter(self):

''' Gibt das Alter zurück ‘‘‘

return self.__Alter # Gekapseltes Attribut

Das Attribut __Alter ist gekapselt, man kann nur durch die Methode ge-
tAlter auf das Attribut zugreifen, nicht über den Befehl mensch1.__Alter
print(mensch1.getAlter()) # Gibt das Alter aus

print(mensch1.__Alter()) # ERROR, da gekapseltes Attribut

Ziel dabei ist es, wie im Kapitel Kapselung von Klassen bereits beschrieben, ledig-
lich einen kontrollierten Zugriff zuzulassen.

Die set-Methode ist analog zur get-Methode aufgebaut:


def setAlter(self,alter_neu):

''' Setzt das Alter'''

self.__Alter=alter_neu

Objektorientieres Programmieren OOP 71


Die Methode setAlter benötigt als weitere Übergabe-Variable das neue Alter.
Die Funktion wird wieder durch das Objekt aufgerufen.
mensch1=Mensch("Tom", 26, 1.84) #Erstellt das Objekt mensch1

print("Alter:",mensch1.getAlter()) # Gibt das Alter aus

mensch1.setAlter("27") # Setzt das neues Alter

print("Neues Alter:", mensch1.getAlter()) # Gibt das neue Alter aus

Abbildung 35 Ausgabe vor und nach dem setAlter-Befehl

Durch Methoden kann klar definiert werden, welche Regeln für Daten
innerhalb eines Objektes gelten. Es können Daten ausgegeben, verän-
dert oder unzugänglich gemacht werden.

Methoden können auch deutlich komplexer aufgebaut sein. Sie sind genau wie
Funktionen codetechnisch nicht limitiert.
Eine weitere Standard-Methode ist die del-Methode.

5.5. __del__ Methode


Die Funktion del ist uns bereits von Listen und Variablen bekannt. Mit ihr können
nicht nur Variablen, sondern auch Objekte löschen.
del mensch1

Das Objekt wird aus dem Speicher entfernt. Die Methode ist, ähnlich wie eine
Standard-Funktion, im Interpreter integriert und bei der Installation automatisch
eingefügt worden. Damit kann man die Methode auf jede Klasse anwenden, und
muss diese nicht in der Klasse definieren.

Wir können die Methode del innerhalb einer Klasse erweitern, um beispielsweise
weitere Aktionen anzustoßen, wenn ein Objekt gelöscht wird.

Dafür wird innerhalb der Methode eine Funktion angelegt mit dem Namen
__del__.

72 Objektorientieres Programmieren OOP


Wenn der del-Befehl auf ein Objekt der Klasse angewendet wird, wird
gleichzeitig automatisch die __del__ Methode aufgerufen.

Das kann man nutzen, um beispielsweise eine Meldung auszugeben, dass das
Objekt gelöscht wurde.

Der Aufbau der del-Methode ist analog zu einer normalen Methode. Auch hier
ist der erste Übergabewert self.
def __del__(self):

print("Das Objekt wurde erfolgreich gelöscht")

del mensch1

Abbildung 36 Ausgabe beim Löschen des Objekts über die del-Methode

Hiermit wurden die wichtigsten Eigenschaften von Klassen und Methoden erläu-
tert. Jetzt geht es an die nächste Übung, in der wir das Kapseln von Variablen
und das Anlegen von Methoden trainieren.

5.6. Übung – Passwortschutz


Wie bereits erwähnt, ist das objektorientiere Programmieren eines der Kern-
stücke von Python. Daher wollen wir den Umgang mit diesen Elementen üben.
Dazu soll die Klasse Mensch um das Attribut Passwort erweitert werden. Alle
Daten wie Name, Alter und Größe sollen auf privat gesetzt werden, daher kann
man die Attribute nicht einfach auslesen oder verändern.

Erstelle anschließend eine Methode, welche nach Eingabe (Übergabe) des Pass-
worts alle gekapselten Attribute ausgibt. Wenn das Passwort falsch eingegeben
wurde, erscheint eine Fehlermeldung.
Die Unterscheidung, ob das Passwort richtig oder falsch ist, soll mit einer if-Ab-
frage realisiert werden.

5.7. Lösung
Zunächst erstellen wir die bekannte Klasse Mensch. Anschließend legen wir den
Konstruktor an und übergeben ihm die Attribute der Klasse. Zusätzlich fügen
wir das neue Attribut Passwort hinzu.
class Mensch:

'''Erstellung des Objekts Mensch'''

def __init__(self, name, alter, größe, passwort):

Objektorientieres Programmieren OOP 73


'''Die Argumente des Menschen werden definiert

(string) Name: Name des Menschen

(int) alter: Alter des Menschen

(float) Größe: Größe des Menschen

(string) Passwort: Passwort um Daten abzurufen

'''

self.__Name=name #Speichern der übergebenen Variablen

self.__Alter=alter

self.__Größe=größe

self.__Passwort=passwort

Da die Klasse um das Attribut Passwort erweitert wurde, muss auch ein Argu-
ment mehr übergeben werden. Im Beispiel sind alle Attribute privat. Notwen-
dig ist es lediglich beim Attribut Passwort.

Der erste Teil der Aufgabe ist bereits abgeschlossen.


Als nächstes legen wir die Methode an, um das eingegebene mit dem vorhan-
denen Passwort abzugleichen. Ein passender Name dafür ist checkPasswort
oder auch kürzer: checkPW.

Die Methode zur Abfrage des Passworts muss eine Variable passwort überge-
ben bekommen.
Nicht verwechseln, die Übergabevariable passwort wird aus dem
Hauptprogramm übergeben. Die Variable __Passwort ist eine private,
interne Variable der Klasse.
def checkPasswort(self,passwort):

'''Prüft ein eingegebenes Passwort

Gibt bei Erfolg die Daten der Klasse aus

'''

if passwort==self.__Passwort:

print('Das Passwort war korrekt')

print('Der Name lautet:',self.__Name)

print('Das Alter ist:',self.__Alter)

print('Die Größe ist:',self.__Größe)

else:

print('Das Passwort war nicht korrekt')

74 Objektorientieres Programmieren OOP


Es wird mit Hilfe der if-Abfrage geprüft, ob die übergebene Variable mit dem in-
ternen Passwort übereinstimmt. Im positiven Fall werden die Daten ausgege-
ben, ansonsten erscheint die Fehlermeldung.

Um die Methode zu testen, erstellen wir ein Objekt mensch1 der Klasse
Mensch. Das Attribut Passwort wird mit Python3 festgelegt.

Anschließend fordern wir den Benutzer auf, das Passwort einzugeben. Dieses
speichern wir in der Variablen pass_in.
pass_in = eval(input("Geben S ie das Passwort ein \n ",))

Danach wird die Methode ckeckPasswort aufgerufen. Ihr wird das zu prüfende
Passwort übergeben. Wir wenden die Methode auf das Objekt mensch1 an.
Als Rückgabewert erhalten wir die Daten des Objekts mensch1, oder eine Mel-
dung, dass das Passwort falsch war.
mensch1=Mensch("Tom", 26, 1.84,"Python3") #Das Passwort ist Python3

pass_in = eval(input("Geben Sie das Passwort ein \n ",))

mensch1.checkPasswort(pass_in)

Sehen wir uns den gesamten Programmcode noch einmal an.


''' Übung Klassen Passwortschutz'''

class Mensch:

'''Erstellung des Objekts Mensch'''

def __init__(self, name, alter, größe, passwort):

'''Die Argumente des Menschen werden definiert

(string) Name: Name des Menschen

(int) alter: Alter des Menschen

(float) Größe: Größe des Menschen

(string) Passwort: Passwort um Daten abzurufen

'''

self.__Name=name #Speichern der Ãœbergebenen Variab-len

self.__Alter=alter

self.__Größe=größe

self.__Passwort=passwort

def checkPasswort(self,passwort):

'''Prüft ein eingegebenes Passwort

Objektorientieres Programmieren OOP 75


Gibt bei erfolg die Daten der Klasse aus

'''

if passwort==self.__Passwort:

print('Das Passwort war korrekt')

print('Der Name lautet:',self.__Name)

print('Das Alter ist:',self.__Alter)

print('Die Größe ist:',self.__Größe)

else:

print('Das Passwort war nicht korrekt')

mensch1=Mensch("Tom", 26, 1.84,"Python3") #Das Passwort ist Python3

pass_in = str(input("Geben Sie das Passwort ein \n ",))

mensch1.checkPasswort(pass_in)

Das Programm wird zweimalig ausgeführt. Zunächst wird ein falsches Passwort
eingegeben, anschließend das korrekte.

Anmerkung: Je nach Spyder-Version kann es bei Zeile 29 zu einer Fehlermeldung


kommen. Alternativ zu eval() kann eine direkte Typumformung mittels str() rea-
lisiert werden. Bei dieser Variante werden keine Anführungszeichen bei der Pass-
worteingabe eingegeben.
pass_in =str(input("Geben Sie das Passwort ein \n ",))

76 Objektorientieres Programmieren OOP


Das Programm kann noch erweitert werden, beispielsweise um den Hinweis,
dass ein neues Passwort eingegeben werden kann, wenn die Eingabe nicht kor-
rekt war und man nicht das Programm neu ausführen muss.

5.8. Klassenvariablen
Alle Variablen bzw. Attribute einer Klasse wurden bisher in der __init__ Methode
festgelegt. Dadurch gelten sie spezifisch für jedes erstellte Objekt. Das ist auch
logisch, schließlich besitzt jedes Objekt seine individuellen Attribute.

Es gibt jedoch auch Eigenschaften, die eine ganze Klasse als Einheit betreffen. In
unserem Beispiel Mensch wäre das die Anzahl an angelegten Personen. Die An-
zahl der existierenden Menschen ist eine Variable, welche nicht objektabhängig
ist, sondern für die ganze Klasse gilt.

In Python lässt sich im Hauptprogramm eine Zählvariable anlegen, die jedes Mal
beim Erzeugen eines neuen Objektes erhöht wird.

Es ist jedoch auch möglich, das Hochzählen der Zählervariablen automatisiert


beim Erzeugen eines Objekts ablaufen zu lassen. Dafür wird innerhalb der Klasse
eine globale Klassenvariable definiert. Diese steht direkt nach dem Klassenauf-
ruf, noch vor dem Konstruktor.
class Mensch:

'''Erstellung des Objekts Mensch'' '

anzahl =0 # globale Klassen-Variable, Startwert Null

def __init__(self, name, alter, größe, passwort):

'''Die Argumente des Menschen werden definiert

...

Die Variable anzahl ist zusätzlich bei jedem erstellten Objekt vorhanden, ohne
dass man sie extra übergeben muss.
mensch1=Mensch("Tom", 26, 1.84,"Python3")

print(mensch1.anzahl)

Die Abfrage print(mensch1.anzahl) gibt den Wert 0 aus, obwohl der


Wert Null explizit nicht beim Erstellen des Objektes mensch1 übergeben
wurde.

Die globale Variable anzahl ist noch für jedes Objekt gleich – Nämlich 0!
Noch wird die Variable nicht verändert und zeigt daher nicht die aktu-
elle Anzahl an erzeugten Objekten/Datensätzen.

Objektorientieres Programmieren OOP 77


Ebenso kann man direkt über die Klasse auf den Wert der Klassen-Variablen zu-
greifen. Dafür muss zuvor kein Objekt erstellt werden. Dazu wird der Name der
Klasse geschrieben, gefolgt von einem Punkt und der Variablen.
print(Mensch.anzahl) # Gibt ebenfalls 0 aus

Interessant werden Klassenvariablen, wenn man sie mit Methoden kombiniert.

Beispielsweise können die __init__ und __del__ Methode erweitert werden, so-
dass die Zählvariable beim Anlegen oder Löschen eines Objekts hoch- oder run-
tergezählt wird.
Mensch.anzahl =Mensch.anzahl +1

Für den Ausdruck x=x+1 kann man abgekürzt auch x+=1 schreiben und
analog für x=x-1 den Ausdruck x-=1

Das verkürzt den Befehl zu


Mensch.anzahl +=1

Zusätzlich können weitere Befehle hinzugefügt werden, beispielsweise


print('Es wurde ein neuer Mensch geboren, es existieren nun', Mensch.anzahl, "Men-
schen")

Jedes Mal, wenn ein Objekt initialisiert wird, wird zusätzlich diese Meldung mit
der neuen Anzahl ausgegeben.

Die Klasse Mensch wurde mit den Methoden und der Klassen-Variable erweitert.
class Mensch:

'''Erstellung des Objekts Mensch'''

anzahl=0 # globale Klassen-Variable, Startwert Null

def __init__(self, name, alter, größe, passwort):

'''Die Argumente des Menschen werden definiert

(string) Name: Name des Menschen

(int) alter: Alter des Menschen

(float) Größe: Größe des Menschen

'''

Mensch.anzahl+=1 # Erhöhe Klassen -Variable um 1

print('Es wurde ein neuer Mensch geboren, es existieren nun',Mensch.anzahl,


"Menschen")

self.__Name=name #Speichern der übergebenen Variablen

self.__Alter=alter

78 Objektorientieres Programmieren OOP


self.__Größe=größe

self.__Passwort=passwort

def __del__(self):

Mensch.anzahl-=1 # Verringere Klassen-Variable um 1

print("Das Objekt wurde erfolgreich gelöscht")

print('Ein Mensch ist gestorben, es existieren nun',Mensch.anzahl,"Menschen")

Zur Veranschaulichung werden drei Objekte angelegt.


mensch1=Mensch("Tom", 26, 1.84,"Python3")

mensch2=Mensch("Lisa", 28, 1.67,"Pyth on3")

mensch3=Mensch("Kevin", 34, 1.87,"Python3")

del mensch1

Bei jeder Initialisierung wird Mensch.anzahl um eins erhöht und der Wert ausge-
geben. Anschließend wird beispielhaft ein Objekt gelöscht. Dabei wird die Klas-
senvariable um eins verringert und ebenfalls ausgegeben.

Abbildung 37 Ausgabe der Variable Mensch.Anzahl

Klassenvariablen stellen ein Werkzeug dar, um ein gemeinsames Attribut aller


Objekte festzulegen. Genau darum geht es in der nächsten Programmierübung:
Das Erweitern der Klasse Mensch.

5.9. Übung - Durchschnittsgröße


Die Durchschnittsgröße aller Menschen einer Einheit ist eine Variable, welche
sich auf die ganze Klasse Mensch bezieht. Trotzdem hängt der Wert von allen
existierenden Objekten ab. In dieser Übung erweitern wir die Klasse Mensch um
die Klassenvariable Durchschnittskörpergröße aller Objekte.

Bei der Erstellung eines neuen Objekts wird die Durchschnittsgröße neu berech-
net. Dafür benötigen wir die Variable anzahl, welche zuvor eingeführt wurde.

Objektorientieres Programmieren OOP 79


Außerdem brauchen wir zwei weitere Klassenvariablen, eine zur Speicherung der
Summen aller Körpergrößen und eine andere zur Darstellung des Durchschnitts.
Dabei gilt:
größe_gesamt
größe_mittel =
Anzahl Menschen
Die Berechnung kann im Konstruktor stattfinden, nachdem ein Objekt erstellt
wurde.

Außerdem muss dieselbe Berechnung durchgeführt werden, nachdem ein Ob-


jekt gelöscht wurde.

5.10. Lösung
Zunächst werden die Klassenvariablen angelegt und ihnen der Wert Null zuge-
ordnet. Die Variablen wurden dabei sinnvoll abgekürzt:
class Mensch:

'''Erstellung des Objekts Mensch'''

anzahl=0 # Globale Klassenvariable, Startwert Null

gr_ges=0 # Gesamtgröße aller Menschen

gr_schnitt=0 #Durchschnittliche Größe aller Menschen

Als nächstes passen wir die Methode __init__ an.

Jedes Mal, wenn ein neues Objekt erstellt wird, wird die übergebene Größe auf-
summiert und eine neue Durchschnittsgröße berechnet.
def __init__(self, name, alter, größe, passwort):

'''Die Argumente des Menschen werden definiert

(string) Name: Name des Menschen

(int) alter: Alter des Menschen

(float) Größe: Größe des Menschen

'''

Mensch.anzahl+=1 # Erhöhe Klassen -Variable um 1

print('Es wurde ein neuer Mensch geboren,

es existieren nun’, Mensch.anzahl,"Menschen")

self.__Name=name #Speichern der übergebenen Variablen

self.__Alter=alter

80 Objektorientieres Programmieren OOP


self.__Größe=größe

self.__Passwort=passwort

Mensch.gr_ges+=größe #Gesamtgröße neu berechnen

Mensch.gr_schnitt=Mensch.gr_ges/Mensch.anzahl

#Durchschnitt neu berechnen

Zum Berechnen der Gesamtgröße aller Objekte verwenden wir die übergebene
Variable größe. Alternativ eignet sich auch self.__Größe, da die Variable zwei Zei-
len zuvor den gleichen Wert zugewiesen bekommen hat.

Die Werte werden aufsummiert und anschließend wird der Wert gr_schnitt be-
rechnet. Wir sehen, dass wir durch den Aufruf Mensch.gr_schnitt auf den ge-
wünschten Wert zugreifen können.

Optional können wir eine Ausgabe hinzufügen. Dabei wird die Durchschnitts-
größe wiederum auf zwei Nachkommastellen gerundet.
print('Die Durchschnittsgröße beträgt nun', round(Mensch.gr_schnitt,2),)

Anschließend führen wir das gleiche Prozedere für die __del__ Methode durch.
Diese wird durch die gleichen Befehle ergänzt. Zunächst wird die Gesamtgröße
berechnet und anschließend die Durchschnittsgröße.
def __del__(self):

Mensch.anzahl-=1 # Verringere Klassen-Variable um 1

print('Ein Mensch ist gestorben, es existieren nun',Mensch.anzahl,"Menschen")

Mensch.gr_ges-=self.__Größe #Gesamtgröße neu berechnen

Mensch.gr_schnitt=Mensch.gr_ges/Mens ch.anzahl #Durchschnitt neu berech-


nen

print('Die Durchschnittsgröße beträgt nun',round(Mensch.gr_schnitt,2),)

Als letztes wird ein print()-Befehl ergänzt.

Die Ausgabe wird durch die gleichen Aufrufe wie beim vorherigen Beispiel aus-
geführt.
mensch1=Mensch("Tom", 26, 1.84,"Python3")

mensch2=Mensch("Lisa", 28, 1.67,"Python3")

mensch3=Mensch("kevin", 34, 1.87,"Python3")

del mensch1

Objektorientieres Programmieren OOP 81


Die Ausgabe zeigt dabei:

Abbildung 38 Ausgabe der Durchschnittsgröße

Klassen, Objekte, Objekt- und Klassenvariablen sind bekannt. Als nächstes


schauen wir uns ein weiteres, großes Themenfeld der objektoptimierten Pro-
grammierung an, die Vererbung von Klassen.

5.11. Vererbung
Die Einteilung von Objekten aus der realen Welt in Klassen ist übersichtlich und
leicht zu verstehen. Sehen wir ein neues Objekt, beispielsweise eine neue Per-
son, sucht das Gehirn Gemeinsamkeiten und Unterschiede zu uns bereits be-
kannten, eingespeicherten Objekten. Diese Gemeinsamkeiten werden mit Erfah-
rungswerten abgeglichen, wodurch eine Einteilung, besser bekannt als „der
erste Eindruck“ einer Person innerhalb von wenigen Sekunden erfolgt.

Unsere Welt ist ein riesiges, komplexes System, bei dem viele Klassen sich ge-
genseitig beeinflussen. Deshalb ordnet unser Gehirn Objekte nicht nur in ein-
zelne Klassen, sondern verschiedene Unter- und Überklassen an.

Als Beispiel gibt es bei der Überklasse Mensch verschiedene Unterklassen. Dabei
kann die Einteilung nach geografischer Herkunft (Asiaten, Europäer, Afrikaner,
…), Alter (Babys, Kinder, Jugendliche, Erwachsene, …) oder anderen Aspekten wie
dem Beruf (Künstler, Ingenieure, Programmierer, …) eingeteilt werden. Man
spricht dabei auch von Kindsklassen und Elternklassen.

Die einzelnen Kindsklassen haben zum einen alle die gleichen Attribute wie die
Überklasse, können jedoch noch zusätzliche, individuelle Klassen-Attribute be-
sitzen.

Wenn man diesen Zusammenhang in die objektorientierte Programmierung


überträgt, spricht man von Vererbung.

82 Objektorientieres Programmieren OOP


Die Unterklassen erben dabei Attribute und Methoden der übergeord-
neten Klasse. Vor der Anlage einer untergeordneten Klasse muss zu-
nächst die übergeordnete Klasse erstellt sein.

Das Erstellen der Unterklasse ist vom Aufbau identisch mit dem Erstellen der
übergeordneten Klasse. Jedoch muss nach dem Klassennamen der Unterklasse
der Name der Überklasse angegeben werden.

Als Beispiel erstellen wir eine Unterklasse der Klasse Mensch. Diese beinhaltet
begeisterte Python-Fans, daher ist ein passender Name der Kindsklasse Pro-
grammierer.
class Programmierer(Mensch):

Nachdem die Unterklasse angelegt wurde, wird wieder der Konstruktor der
Klasse angeführt. In diesem werden die Argumente der Überklasse und optional
weitere für die Unterklasse übergeben. Im Beispiel erhält die Unterklasse Pro-
grammierer ein zusätzliches Attribut. Das Attribut prog_spr steht dabei für eine
Programmiersprache des Programmierers.
def __init__(self, name, alter, größe, prog_spr):

Anschließend muss der Konstruktor der Überklasse aufgerufen werden.


Dadurch wird ein Objekt der Überklasse innerhalb der Unterklasse er-
stellt.
Mensch.__init__(self, name, alter, größe)

Nachdem das Objekt initialisiert wurde, kann das Attribut prog_spr definiert
werden.
self.Prog_spr=prog_spr

Bei Unterklassen ist die Dokumentation, also die Docstrings, noch mehr von Be-
deutung, da man schnell übersehen kann, dass es sich um eine Unterklasse han-
delt. Es empfiehlt sich immer, Kindsklassen u.ä. deutlich zu kennzeichnen.

Nachdem die Unterklasse definiert wurde, können wir wie gewohnt Methoden
erstellen, beispielsweise die set- und get-Methoden für den neuen Wert
prog_spr sowie die __del__ Methode. Die set- und get-Methoden sind hierbei
nicht zwingend notwendig, da die Variable prog_spr nicht gekapselt ist. Wir kön-
nen ihren Wert einfach überschreiben oder auslesen. Trotzdem werden beide
Methoden beispielhaft angelegt.

Beim folgenden Programmcode wird die Oberklasse auf das Wesentliche redu-
ziert. Die Passwort- und Durchschnittsgrößenerweiterung aus den Beispielen
und Übungen zuvor werden aufgrund der Übersichtlichkeit wieder entfernt.
Der Fokus liegt auf der untergeordneten Klasse.

Objektorientieres Programmieren OOP 83


class Mensch:

''' Erstellung des Objekts Mensch

Klassen-Variablen

'''

def __init__(self, name, alter, größe):

''' Die Argumente des Menschen werden definiert

(string) Name: Name des Menschen

(int) alter: Alter des Menschen

(float) Größe: Größe des Menschen '''

self.__Name=name #Speichern der übergebenen Variablen

self.__Alter=alter

self.__Größe=größe

class Programmierer(Mensch):

''' Die Klasse Programmierer ist eine Unterklasse der Klasse Mensch

Die Klasse hat folgende Attribute geerbt:

(string) Name: Name des Menschen

(int) alter: Alter des Menschen

(float) Größe: Größe des Menschen '''

def __init__(self, name, alter, größe, prog_spr):

''' Klassenspezifisches Attribut

(string) prog_spr: Beher rschte Programmiersprache '''

Mensch.__init__(self, name, alter, größe)

self.Prog_spr=prog_spr

def getProg_spr(self):

''' Gibt aktuelle Programmiersprache aus '''

return self.Prog_spr

def setProg_spr(self,prog_spr_neu):

'''

Setzt neue Programmiersprache

'''

self.Prog_spr=prog_spr_neu

84 Objektorientieres Programmieren OOP


def __del__(self):

print('Leider haben wir einen Programmierer verloren')

Im Hauptprogramm können wir weiterhin wie gewohnt ein Objekt er-


stellen und die Methoden der Ober und Unterklassen verwenden.

programmierer1=Programmierer('Tom',26,1.84,'Python')

print(programmierer1.getProg_spr())

del programmierer1

Der Programmierer programmierer1 wird erstellt. Er besitzt alle Attribute der


Oberklasse und zusätzlich die Programmiersprache Python.
Anschließend wird die Methode getProg_spr() ausgeführt. Durch Ausführung
der Methode erhalten wir den Wert der Programmiersprache, in unserem Fall
Python.

Als letztes wird die del Methode ausgeführt und das Objekt gelöscht.

5.12. Klassen auslagern


Das vorherige Beispiel zeigt, dass Klassen einen enormen Zeilenbedarf haben.
Obwohl es eine simple Unterklasse war, bei der wir für lediglich ein Attribut eine
get und eine set Methode erstellt haben, ist über eine ganze Taschenbuchseite
voll Code entstanden.

In der Spyder-Benutzeroberfläche kann man aus diesem Grund den Quelltext der
Klassen ein- und ausklappen.

Abbildung 39 Ein- und Ausklappen des Programmcodes in Spyder

Diese Lösung funktioniert, jedoch ist die Optik bei mehreren Klassen immer noch
unschön und viele Benutzeroberflächen unterstützen diese Funktion nicht.

Objektorientieres Programmieren OOP 85


Eine geschicktere Variante ist es daher, genau wie bei Funktionen, die
Klassen in eine externe Datei auszulagern.

Die Klassen Mensch und die Unterklasse Programmierer werden dabei in eine
eigene Datei modul_klassen.py abgespeichert.

Im Hauptprogramm gibt es anschließend viele verschiedene Möglichkeiten, das


Modul bzw. die Klassen des Moduls zu importieren. Zunächst über den bereits
bekannten Befehl:
import modul_klassen

Dabei wird das gesamte Modul importiert. Um auf die Klassen zugreifen zu kön-
nen, muss der Pfad angegeben werden. Auch das ist uns bereits von Vorgehens-
weisen wie dem Auslagern von Funktionen in Module bekannt.
# Zugriff über Modulname.Klassenname

mensch1= modul_klassen.Mensch("Tom", 26, 1.84)

programmierer1 = modul_klassen.Programmierer("Tom", 26, 1.84,‘Python‘)

Dabei muss darauf geachtet werden, dass der Pfad anzugeben ist. Liegt
die Datei modul_klassen in einem Unterordner, muss dieser wiederum
vorangestellt sein.
Unterordner.Modulname.Klasse

Diese Notation ist sehr mühselig, daher gibt es noch alternative Varianten zum
Import der Klassen, welche sich auch auf Module mit Funktionen anwenden las-
sen.

Mit dem Befehl from Modulname import Klassenname kann eine einzelne Klasse
importiert werden.
from modul_klassen import Mensch

Der große Vorteil dabei ist, dass wir nicht den Pfad angeben müssen. Wir können
die Klasse verwenden, als stünde sie im selben Programm.
mensch1= Mensch("Tom", 26, 1.84)

Es können auch mehrere Klassen und Unterklassen gleichzeitig impor-


tiert werden. Die verschiedenen Klassen werden dabei mit einem
Komma getrennt.
from modul_klassen import Mensch, Programmierer

Auch hier können wir die Klassen ohne Modulnamenangabe verwenden


# Zugriff über Modulname.Klassenname

86 Objektorientieres Programmieren OOP


mensch1= modul_klassen.Mensch("Tom", 26, 1.84 )

programmierer1 = modul_klassen.Programmierer("Tom", 26, 1.84,‘Python‘)

Der Nachteil bei dieser Variante ist, dass man jede Klasse einzeln angeben muss.
Wenn man mehrere Klassen und Kinderklassen verwenden möchte, müssen alle
aufgeführt werden.

Eine Abkürzung für die Angabe aller Klassen bietet der Stern-Operator. Durch
den Befehl
from modul_klassen import*

werden alle Klassen des Moduls modul_klassen geladen und können ohne Anga-
ben des Moduls verwendet werden.

Der Nachteil beim Verwenden dieser Methode ist, dass man beim Importieren
von mehreren Modulen nicht weiß, in welchem Modul die verwendete Klasse
steht. Außerdem ist es für das Verständnis des Programmcodes verwirrend,
wenn in einer Zeile plötzlich ein Objekt mit einer Klasse angelegt wird, welche
vorher nirgends konkret zu sehen war. Dem kann man mit einer ausführlichen
Dokumentation entgegenwirken. Trotzdem empfiehlt es sich, wenn nur wenige
Klassen benötigt werden, diese durch konkretes Nennen des Namens zu impor-
tieren.
from modul_klassen import Mensch, Programmierer

Mit diesem Befehl ist klargestellt, dass die Klassen Mensch und Programmierer
aus dem Modul modul_klassen stammen. Außerdem weißt einen unsere Pro-
grammierumgebung Spyder durch eine Warnung (kein Error) hin, dass wir den
Sternoperator verwendet haben.

Das Auslagern von Klassen ist dem von Funktionen weitestgehend identisch. In
der nächsten Übung legen wir den Fokus noch einmal auf Klassen und Unterklas-
sen. Dabei wird ein bekanntes Glücksspiel hinzugezogen.

5.13. Übung – Lottospielen


Das bekannte Spiel „6 aus 49“ ist perfekt geeignet, um die Themenfelder wie
Schleifen, Listen und Klassen zu trainieren.

Beim Lotto 6 aus 49 werden nach dem Zufallsprinzip 6 Zahlen aus der Zahlen-
reihe von 1 bis 49 gezogen. Ergänzungen wie Zusatz- und Superzahlen werden
bei diesem Beispiel nicht berücksichtigt.

Für die Übung wird die Aufgabe in folgende Teilbereiche untergliedert:

1. Erstelle eine Klasse Lottospieler

Objektorientieres Programmieren OOP 87


Die Klasse besitzt die Attribute Name und Zahlen. In Name wird der Name des
Spielers gespeichert. In Zahlen wird eine Liste mit sechs Zahlen, welche beim
Erzeugen eines Spielers übergeben werden, hinterlegt. Diese entsprechen den
vom Spieler angekreuzten Zahlen auf dem Lottoschein.

2. Lege danach eine Methode check_gewinn an, welche die eigenen Lottozahlen
mit den Gewinnzahlen vergleicht und die Anzahl der Treffer zurückgibt. Am ein-
fachsten kann man das durch eine for-Schleife realisieren, welche für jede Ge-
winnzahl eine if-Abfrage durchführt.

Der Befehl x in liste gibt True zurück, wenn das Element x in der Liste
liste vorkommt, ansonsten False. Damit können wir prüfen, ob eine Ge-
winnzahl mit den eigenen Zahlen übereinstimmt.

3. Lege insgesamt drei verschiedene Spieler (Objekte) mit verschiedenen Namen


und Lottozahlen an.

4. Erstelle eine Liste mit den Zahlen 1 bis 49.

5. Wähle 6 zufällige Zahlen aus 49 aus.

Verwende dafür die Funktion random.sample(liste,n). Sie gibt n zufäl-


lige Zahlen aus der Liste liste zurück. Dafür muss das Modul random im-
portiert werden.

6. Vergleiche die Gewinnerzahlen mit den Zahlen der Lottospieler (Entspricht


dem Aufrufen der Funktion check_gewinn).

7. Lasse die Namen und die Anzahl an Treffern für jeden Spieler ausgeben.

Da neue Funktionen verwendet werden und die Abfolge der Befehle etwas kom-
plexer ist als die vorherigen Beispiele, kann die folgende Schablone als Hilfestel-
lung dienen. Es gibt, wie immer beim Programmieren, noch unzählige weitere
Möglichkeiten.
import random

class Lottospieler:

'''

Erstellung des Objekts Lottospielers

Klassen-Variablen

'''

def __init__(self,name,zahlen):

'''

88 Objektorientieres Programmieren OOP


Die Argumente des Spielers werden definiert

(string) Name: Name des Spielers

(liste) Zahlen: Liste mit den Lottozahlen des Spielers

'''

def check_gewinn(self,gewinn_zahlen):

'''

Die Lottozahlen des Spielers werden

mit übergebenen Gewinnzahlen verglichen.

Es wird die Anzahl der Treffer zurückgegeben

'''

### HAUPTPROGRAMM###

'''Erzeugen der Gewinnzahlen'''

lottozahlen =range(1,50)

gewinn_zahlen = random.sample( ……)

'''Erzeugen der Spieler'''

'''Ausgabe der Gewinner'''

5.14. Lösung
Zunächst importieren wir das Modul random, damit die Funktion sample() ver-
wendet werden kann. Das Modul ist beim Download von Anaconda automatisch
heruntergeladen worden. Da es nicht zu den Built-in-Bibliotheken gehört, müs-
sen wir es importieren.
import random

Anschließend wird die Klasse Lottospieler erstellt. Sie besitzt keine Klassenvari-
ablen.

Danach weisen wir in der Methode __init__ die Attribute name und zahlen zu.
import random

class Lottospieler:

Objektorientieres Programmieren OOP 89


'''

Erstellung des Objekts Lottospielers

Klassen-Variablen

'''

def __init__(self,name,zahlen):

'''

Die Argumente des Spielers werden definiert

(string) Name: Name des Spielers

(liste) Zahlen: Liste mit den Lottozahlen des Spielers

'''

self.Name=name

self.Zahlen=zahlen

Somit wurde zwar die Klasse angelegt, jedoch fehlt noch die Methode check_ge-
winn.

Der Methode werden die Gewinnzahlen in einer Liste mit sechs Elementen über-
geben.

Jedes Element der eigenen Liste Zahlen wird mit den Gewinnzahlen abgeglichen.
Dafür wird eine for-Schleife verwendet. Falls das Element gleich ist, wird die Zähl-
variable treffer um eins erhöht.
def check_gewinn(self,gewinn_zahlen):

'''

Die Lottozahlen des Spielers werden

mit übergebenen Gewinnzahlen verglichen.

Es wird die Anzahl der Treffer zurückgegeben

'''

treffer=0 # Zunächst keinen Treffer

for x in gewinn_zahlen: # Für jedes Element in gewinn_zahlen

if x in self.Zahlen: # Wenn Gewinnzahl x vorhanden

treffer+=1 # Treffer +1

return treffer # Gibt Anzahl der Treffer zurück

90 Objektorientieres Programmieren OOP


In dieser if-Anweisung ist keine elif oder else Anweisung vorhanden.
Diese ist nicht notwendig. Ist die Bedingung nicht erfüllt, wird die Zeile
treffer+=1 übersprungen und direkt der Wert treffer zurückgegeben.

Mit der Methode check_gewinn ist die Klasse vollständig definiert.

Anschließend erzeugen wir die Gewinnerzahlen mit der range() und der sample()
Funktion
lottozahlen =range(1,50) # Erzeugt eine Liste von 1 -49

# Erzeugt eine Liste mit 6 zufälligen

gewinn_zahlen = random.sample(lottozahlen,6)

Nachdem die Gewinnzahlen/Lottozahlen „gezogen“ wurden, werden drei Lotto-


spieler erstellt.

Diese erhalten sechs individuelle Glückszahlen, welche wir selbst festlegen kön-
nen. Im Beispiel wurden zur Vereinfachung sechs aufeinanderfolgende Zahlen
gewählt.
'''Erzeugen der Spieler'''

lottospieler1=Lottospieler('Tom',[1,2,3,4,5,6])

lottospieler2=Lottospieler('Lisa',[7,8,9,10,11,12])

lottospieler3=Lottospieler('Kevin',[13,14,15,16,17,18])

Als letztes wird durch den Befehl


lottospieler1.Name

auf den Namen des Spielers zugegriffen und die Anzahl der Treffer seiner Zahlen
durch den Methodenaufruf
lottospieler1.check_gewinn(gewinn_zahlen)

geprüft. Das alles wird in einen print-Befehl für alle Spieler gleichermaßen aus-
gegeben.
'''Ausgabe der Gewinner'''

print("Gewinnerzahlen sind:",gewinn_zahlen)

print(lottospieler1.Name,"hat",lottospieler1.check_gewinn(gewinn_zahlen),"richtige
Zahlen")

print(lottospieler2.Name,"hat",lottospieler2.check_gewinn(gewinn_za hlen),"richtige
Zahlen")

print(lottospieler3.Name,"hat",lottospieler3.check_gewinn(gewinn_zahlen),"richtige
Zahlen")

Objektorientieres Programmieren OOP 91


Anmerkung:

Generell ist es sinnvoller, Variablennamen abzukürzen, beispielsweise lt_sp1


statt lottospieler1. Die Namen der Variablen wurden jedoch extra sehr ausführ-
lich gewählt, damit der Programmcode leichter nachzuvollziehen ist. Vor allem
am Anfang ist das wichtiger als die Kompaktheit des Programms.

Damit sind wir auch schon am Ende aller wichtigen Elemente und Bausteine der
Python Programmierung. Variablen, Listen, Schleifen, Klassen, Vererbung - wir
haben alle Themengebiete behandelt und kleinere Beispiele dazu programmiert.

Alles, was jetzt folgt, ist lediglich das Importieren und Anwenden von bereits be-
stehenden Funktionen. Darauf liegt auch der Fokus von Python. Wir können be-
stehende Module verwenden, um nahezu jede Problemstellung zu lösen.

Nachdem wir die Grundlagen behandelt haben, beschäftigen wir uns mit der op-
tischen Gestaltung des Programms, beispielsweise anhand von grafischen Benut-
zeroberflächen. Dafür müssen wir lediglich vorhandene Funktionen bzw. Metho-
den korrekt anwenden können. Hierzu stehen uns viele verschiedene Möglich-
keiten und Bibliotheken zur Verfügung. Im folgenden Kapitel wird auf die meist-
verwendete Bibliothek zurückgegriffen, welche zudem am geeignetsten für An-
fänger ist.

92 Objektorientieres Programmieren OOP


6. Grafische Oberflächen erzeugen
Bisher wurde die Kommunikation mit dem Benutzer eines Programms lediglich
über die Konsole realisiert. Deren Vorteile liegen darin, dass man schnell mit der
Programmierung beginnen kann und sehr codeorientiert arbeitet. Jedoch ist die
Darstellung nicht zeitgemäß und die Ein- und Ausgabemöglichkeiten sind sehr
begrenzt. Vergisst man beispielsweise bei der Eingabe ein Anführungszeichen
oder schreibt eine Variable klein statt groß, kann ein solcher Fehler das ganze
Programm durcheinanderbringen. Es ist sinnvoller, Fenster zu erstellen, bei de-
nen der Benutzer vorgegebene Antworten durch einfaches Klicken eines Buttons
auswählen kann.

Deshalb behandeln wir in diesem Kapitel eine Bibliothek, welche eine grafische
Oberfläche erzeugen kann.

6.1. Tkinter – verschiedene Bausteine


Eine Grafische Benutzeroberfläche GUI (Graphical user interface) bietet zahlrei-
che Möglichkeiten, um Daten benutzerfreundlich darzustellen oder aufzuberei-
ten. Tkinter ist dabei die Schnittstelle zwischen der Programmiersprache Python
und dem GUI-Toolkit TK, welches plattformübergreifend Verwendung findet. Ein
Gui-Toolkit beinhaltet Module, die von anderen Programmierern erstellt wur-
den. Mit Tkinter ist es möglich, Fenster aufzurufen und diese zu gestalten. Dar-
über hinaus existieren noch zahlreiche weitere GUI-Toolkits. Da Tkinter jedoch
weit verbreitetet ist, verwenden wir es für die kommenden Beispiele. Es ist stan-
dardmäßig im Python Interpreter enthalten und muss daher nicht extra instal-
liert werden.

Um Tkinker in das Python-Programm zu importieren, wird der bereits bekannte


import-Befehl verwendet. Da das Tkinter-Modul unzählige Funktionen enthält,
ist es sinnvoll, alle Funktionen über den Aufruf
from tkinter import* #importiert alle Funktionen des Moduls

zu importieren.

In früheren Python Versionen wird tkinter mit einem Großbuchstaben


angeführt. Falls es Probleme beim Importieren gibt, sollte man die Py-
thon Version updaten oder die Schreibweise „Tkinter“ statt „tkinter“
versuchen.

Grafische Oberflächen erzeugen 93


Bei dem Modul Tkinter handelt es sich ebenfalls um ein objektorien-
tiertes Modul. Es arbeitet mit Klassen und Objekten. Jedes von uns er-
zeugte Fenster stellt dabei ein Objekt der Klasse Tk dar. Die Klasse Tk ist
Teil des Moduls Tk und muss nicht separat angelegt werden.

Das Erstellen eines Fensters (window) setzt ein Objekt voraus. Der dazugehörige
Befehl ist entsprechend:
window = Tk()

Die Klasse Tk benötigt dabei keine Übergabewerte.

Nachdem das Objekt erstellt wurde, können verschiedene Methoden auf das Ob-
jekt angewandt werden.

Die essenziellste Methode aus der Klasse Tk ist die Methode main-
loop(). Sie öffnet das Objekt window. Der Befehl muss daher im Haupt-
programm immer als letztes, nach den Einstellungen wie Fenstergröße,
Schrift etc. ausgeführt werden.
window.mainloop()

Nachdem das window-Objekt erstellt wurde, kann die Größe festgelegt werden.
Die benötigte Funktion dafür lautet geometry(). Ihr wird ein String mit der ge-
wünschten Pixelbreite und Pixelhöhe übergeben.
window.geometry(500x200) # 200 Pixel hoch, 500 Pixel breit

Weiterhin wird dem Objekt ein Namen (title) zugewiesen


window.title("Python ohne Vorkenntnisse")

Tkinter ist wie eine Art Baukasten aufgebaut. Das Objekt window bildet die Basis.
Auf dieses Objekt können andere Objekte gesetzt werden.

Beispielsweise kann eine Beschriftung (label) aufgesetzt werden.

Um ein label-Objekt zu erstellen, wird die Klasse Label aus der Tkinter-Bibliothek
verwendet.

Dem Label werden das Objekt, auf welchem der Text gesetzt wird, und der an-
zuzeigende Text übergeben. Das geschieht, indem man der Variablen text den
gewünschten string übergibt.

Ähnlich wie das Fenster muss man anschließend das Label noch aktivieren. Dafür
wird die Funktion pack() verwendet.
label = Label(window,text=“Python Tkinter“)

label.pack(expand=1)

94 Grafische Oberflächen erzeugen


Als Argument setzen wir diesmal expand=1. Das ist immer dann notwendig,
wenn wir das übergeordnete Objekt (window) durch die geometry() Funktion
angepasst haben.

Um das Fenster wie ein gewöhnliches Windows-Fenster aussehen zu lassen fehlt


noch ein Rahmen (frame).

Der Methode Frame() werden das Objekt window sowie die Rahmenart und die
Rahmenbreite übergeben. Danach wird der Rahmen mit dem pack() Befehl akti-
viert. Diesmal müssen die Werte fill='both' und expand=1 aufgerufen werden.
Die Variablen sorgen dafür, dass sowohl die Schrift als auch das eigentliche Fens-
ter eingerahmt wird. Die detaillierte Arbeitsweise ist für den Benutzer unwichtig.

Die entsprechenden Befehle lauten


frame = Frame(window,relief='ridge',borderwidth=20)

frame.pack(fill='both',expand=1)

Nachdem das window, die Beschriftung und der Rahmen erstellt wurden, kön-
nen wir das Programm das erste Mal ausführen. Der vollständige Programmcode
lautet:
from tkinter import* #importiert alle Funktionen des Moduls

window= Tk() #Erstellt das Objekt

window.geometry('500x200') # H=200, B=500

window.title("Python ohne Vorkenntnisse")

label = Label(text='Python Tkinter Übung')

label.pack(expand=1)

frame = Frame(window,relief='ridge',borderwidth=20)

frame.pack(fill='both',expand=1)

window.mainloop()

Grafische Oberflächen erzeugen 95


Abbildung 40 Tkinter Fenster

Wir haben unser erstes Fenster erzeugt.

Zugegeben, dieses ist jedoch noch sehr trist aufgebaut. Es gibt keine Flächen,
Aufforderungen an den Benutzer oder ähnliches. Das wollen wir nun ändern.

Als nächstes wird ein Button erstellt, mit dem man das Fenster wieder schließen
kann. Buttons können für eine breite Palette an Funktionen eingesetzt werden.
Ihr Vorteil liegt in der leichten Programmierung und der benutzerfreundlichen
Optik. Beim Klick auf einen Button wird eine Aktion ausgeführt.

Dafür werden der Methode Button() das Objekt window, der Text des Buttons
sowie die Höhe und Breite übergeben.
button=Button(window,text='EXIT',width=10,height=2)

Es ist wichtig, das übergeordnete Objekt, in diesem Fall das window oder den
frame, zu übergeben.

Anschließend wird der button über den bekannten pack() Befehl aktiviert. Dem
pack() Befehl übergeben wir dabei die Variable side=‘bottom‘. Dadurch wird das
Objekt button am unteren Rand platziert. Es ist auch möglich, ihn oben (top)
oder links und rechts (left / right) zu platzieren.
button.pack(side='bottom')

Führen wir den Programmcode aus, wird der Button angezeigt. Dieser Button
hat jedoch noch keine Funktion. Wir können ihn anklicken und es wird ein opti-
sches Feedback gegeben, jedoch wird keine Funktion ausgeführt.

Als letztes benötigt der Button nämlich noch eine Funktion bzw. Methode, wel-
che beim Anklicken ausgeführt wird.

96 Grafische Oberflächen erzeugen


Eine Methode zum Schließen des offenen Fensters heißt destroy. Um das Objekt
window zu schließen, schreiben wir:
window.destroy

Diesen Befehl müssen wir beim Klicken auf den Button ausführen.

Das dazugehörige Attribut, welches wir im Objekt button setzen müssen, heißt
command. Command wird immer beim Klicken des Buttons automatisch ausge-
führt. Setzen wir command=window.destroy, wird das Fenster geschlossen, so-
bald wir den Button anklicken.
button=Button(window,text='EXIT',width=10,height=2,command=window.destroy)

Abbildung 41 Tkinter Fenster mit Exit-Button

Wir haben dem Button die Funktion destroy zugeordnet. Beim Drücken des
Knopfs schließt sich das Fenster.

Es ist auch möglich, eine eigene Funktion mit dem Button zu verknüp-
fen.

Als Beispiel soll jedes Mal, wenn der Button gedrückt wird, eine Konsolenaus-
gabe stattfinden.

Dafür muss zunächst eine entsprechende Funktion erstellt werden.


def ausgabe():

print("Der Knopf wurde gedrückt")

Anschließend wird die Funktion dem Button zugeordnet.


button=Button(window,text='Klick mich',width=10,command=ausgabe)

Grafische Oberflächen erzeugen 97


Im Unterschied zu einem normalen Funktionsaufruf müssen wir die run-
den Klammern bei der Zuordnung weglassen. Ansonsten wird die Funk-
tion direkt ausgeführt und nicht dem Attribut command zugeordnet.

Nachdem wir die Funktion zugewiesen haben, rufen wir das Fenster auf. Bei je-
dem Klick wird die gewünschte Ausgabe angestoßen.

Abbildung 42 Ausführung der eigenen Funktion über einen Button

Wir haben dem Button eine eigene Funktion zugewiesen.

Als nächstes wird das Programm erweitert. Statt eines print()-Befehls soll der Be-
nutzer aufgefordert werden, Daten einzugeben.

Um ein Eingabefeld zu erzeugen, wird die Klasse Entry() verwendet.


Auch dieses Objekt muss wieder entpackt werden.
eingabe=Entry() #Erzeugt ein Eingabefenster

eingabe.pack()

Der im Eingabefenster eingegebene Wert ist durch den Befehl


eingabe.get()

abrufbar. Diese Abfrage wird in eine Funktion verpackt, welche den Wert gleich
wieder an der Konsole ausgibt.
def einlesen():

print(eingabe.get())

98 Grafische Oberflächen erzeugen


Die Funktion einlesen() gibt den eingelesenen Wert an der Konsole aus. Jetzt
verknüpfen wir lediglich die Funktion einlesen() mit dem Knopfdruck des But-
tons. Das funktioniert über die bekannte Zuweisung
command=einlesen

Damit wird beim Klicken des Buttons der eingelesene Text an der Konsole aus-
gegeben.

Der eingelesene Text wird als string abgespeichert. Möchte man eine
Zahl einlesen, um später mit ihr zu rechnen, muss der Datentyp in int()
oder float() geändert werden.
x= eingabe.get() #Eingelesene Zahl wird als String abgespeichert

x= int(eingabe.get()) #Eingelesene Zahl wird als Int -Zahl abgespeichert

Außerdem ändern wir den Text des Buttons von EXIT zu Einlesen. Der gesamte
Code ergibt sich so zu:
from tkinter import* #importiert alle Funktionen des Moduls

def ausgabe():

print("Der Knopf wurde gedrückt")

def einlesen(): # Gibt den eingelesenen Wert aus

print(eingabe.get())

window= Tk() #Erstellt das Objekt

window.geometry('500x200') # H=200, B=500

window.title("Python ohne Vorkenntnisse")

label = Label(window,text='Python Tkinter Übung')

label.pack(expand=1)

frame = Frame(window,relief='ridge',borderwidth=20)

frame.pack(fill='both',expand=1)

button=Button(window,text='Einlesen',width=10,height=2,command=einlesen)

button.pack(side='bottom')

eingabe=Entry() #Erzeugt ein Eingabefenster

eingabe.pack()

window.mainloop()

Wir starten das Programm, das Fenster öffnet sich. Darin sind der Button sowie
ein Eingabefenster zu sehen. Wir geben einen Beispieltext ein. Beim Klicken des
Buttons wird der Text an der Konsole ausgegeben.

Grafische Oberflächen erzeugen 99


Abbildung 43 Eingabefenster mit Konsolenausgabe

Die Klasse Entry enthält ein Attribut insert. Wenn wir ihr einen String
übergeben, erscheint dieser in der Eingabebox. Dafür muss als erstes
Element eine Null übergeben werden, als zweites Element der ge-
wünschte Text oder die gewünschte Zahl.
eingabe.insert(0,'Standardwert') #Setzt den Wert in das Feld

Das ist hilfreich, um beispielsweise einen Standardwert in das Eingabefeld zu


setzen.

Außerdem können wir die Eingabe-Box gleichzeitig als Ausgabeelement verwen-


den.

Abbildung 44 Eingabebox mit Standardwert

100 Grafische Oberflächen erzeugen


Außerdem kann man die eingegebenen oder ausgegebenen Werte mit der
Funktion
eingabe.delete(0,‘end‘)

löschen. Das ist sinnvoll, wenn man mehrere Aktionen durchführt und sonst die
Eingabe/Ausgabebox überläuft.

Ein-/Ausgabefenster sind essentielle Werkzeuge, um über ein Fenster mit dem


Benutzer zu kommunizieren. Zusätzlich kann immer noch die Konsole miteinbe-
zogen werden.

Als nächstes werden wir noch eine Scrollbar hinzufügen. Das ist ein Feld mit vor-
definierten Auswahlmöglichkeiten. Durch Scrollen im Feld kann man das pas-
sende Element auswählen.

Dafür wird der Befehl


Scrollbar = Scrollbar(window)

aufgerufen. Die Funktion Scrollbar(), welche ebenfalls Element des Tkinter Mo-
duls ist, erhält das Objekt window als Übergabewert. Innerhalb des Feldes soll
eine Box mit einer Liste von Elementen angezeigt werden. Dazu greifen wir auf
die Listbox() Funktion zurück, welche eine Eingangsvariable yscrollcommand
verlangt. Dieser müssen wir unsere Variable scrollbar zuordnen, wobei zusätzlich
ein set-Befehl angehängt werden muss.
listbox=Listbox(window,yscrollcommand=scrollbar.set)

Unsere listbox wurde erstellt. Wir müssen sie jetzt nur noch mit Werten füllen.
Das funktioniert am einfachsten durch den insert-Befehl. Die Elemente sollen an
das Ende gesetzt werden, deshalb übergeben wir den Wert END.

Wir legen eine Liste mit beliebigen Elementen an. Anschließend hängen wir mit
Hilfe einer for-Schleife die einzelnen Elemente der Liste an unsere Listbox an.
listbox=Listbox(window,yscrollcommand=scrollbar.set)

liste1=range(100) #Liste für Listbox 0..100

for element in liste1: # Solange Elemente in der Liste

listbox.insert(END,element) #Listenelement anhängen

Als nächstes müssen wir die scrollbar noch konfigurieren. Das bedeutet, dass wir
sicherstellen, dass sich das Feld beim Scrollen mit der Maus auch gleichzeitig än-
dert. Das bereits bekannte command-Attribut wird hier zu listbox.yview gesetzt
scrollbar.config(command=listbox.yview)

Grafische Oberflächen erzeugen 101


Zuletzt lassen wir beide Objekte anzeigen. Damit die scrollbar und die listbox
aufeinanderliegen, wird bei beiden Objekten side=‘left‘ gesetzt.
listbox.pack(side="left")

scrollbar.pack(side = "left", fill = 'both')

Der gesamte Code sieht damit wie folgt aus:


from tkinter import* #importiert alle Funktionen des Moduls

window= Tk() #Erstellt das Objekt

window.geometry('500x200') # H=200, B=500

window.title("Python ohne Vorkenntnisse")

scrollbar=Scrollbar(window)

listbox=Listbox(window,yscrollcommand=scrollbar.set)

liste1=[1,2,3,4,5,6,7,8,9,10] #Liste für Listbox

for element in liste1: # Solange Elemente in der Liste

listbox.insert(END,element) #Listenelement anhängen

scrollbar.config(command=listbox.yview)

listbox.pack(side="left")

scrollbar.pack(side = "left", fill = 'both')

window.mainloop()

Nach Ausführung des Programms erhalten wir das gewünschte Scrollfeld mit un-
serer Liste als Elemente zum Auswählen.

Abbildung 45 Tkinter Fenster mit Scrollbar und Listbox

Wenn wir das ausgewählte Element nachvollziehen wollen, können wir den In-
dex des Elements bzw. die Reihe, in der die Zahl steht über die Funktion

102 Grafische Oberflächen erzeugen


listbox.curselection()

erhalten.

Als nächstes schauen wir uns die Programmierung von checkboxen bzw. check-
buttons an. Eine checkbox ist ein Feld, das der Benutzer bei einer Abfrage ent-
weder anklicken (checken) oder offen lassen kann. Da die Checkbox lediglich
zwei Zustände besitzen kann (gecheckt oder nicht), wird das Ergebnis eine Vari-
able vom Typ bool, also 1 für True oder 0 für False sein. Diese Variable muss
zuerst angelegt werden. Dafür wird die Funktion IntVar() verwendet.
check=IntVar()

Streng genommen handelt es sich dabei nicht um eine Funktion, sondern um


eine eigene Klasse, welche ein Objekt erzeugt.

Anschließend wird die eigentliche Checkbox erstellt. Diese benötigt als Überga-
bewerte das Fenster, die Variable check und eine Funktion. Die Funktion wird
immer ausgeführt, sobald die Checkbox angeklickt oder die Auswahl wieder ge-
löscht wird.
check=IntVar()

checkbutton=Checkbutton(window,text="Python3",variable=check,command = ein-
lesen)

In unserem Beispiel verwenden wir eine eigene Funktion einlesen(), welche an


der Konsole ausgibt, ob die Checkbox angeklickt wurde oder nicht. Mit Hilfe des
get-Befehls kann der Zustand der Checkbox (True oder False) ermittelt werden.
def einlesen(): # Gibt den eingelesenen Wert aus

if check.get():

print('Checkbox ist ausgewählt')

else:

print('Checkbox ist nicht ausgewählt')

Als letztes wird die Checkbox mit dem pack() Befehl wieder aktiviert.
checkbutton.pack()

Zusammenfassend ergibt sich der Programmcode:


from tkinter import* #importiert alle Funktionen des Moduls

window= Tk() #Erstellt das Objekt

window.geometry('500x200') # H=200, B=500

window.title("Python ohne Vorkenntnisse")

def einlesen(): # Gibt aus ob gecheckt oder nicht

Grafische Oberflächen erzeugen 103


if check.get():

print('Checkbox ist ausgewählt')

else:

print('Checkbox ist nicht ausgewählt')

check=IntVar() #Check-Variable

checkbutton=Checkbutton(window,text="Python3",variable=check,command = ein-
lesen)

checkbutton.pack()

window.mainloop()

Abbildung 46 Tkinter Fenster mit Checkbox

Die Checkbox wird an und abgewählt. Die Konsole gibt währenddessen folgen-
des aus:

Abbildung 47 Konsolenausgabe bei An- und Abwählen der Checkbox

Bei jeder Auswahl oder Abwahl wird die Funktion einlesen() ausgeführt und eine
Konsolenausgabe angestoßen.

104 Grafische Oberflächen erzeugen


Mit der Checkbox haben wir das letzte Element der Tkinter-Familie kennenge-
lernt.

Nachdem wir die wichtigsten Bausteine der grafischen Programmierung behan-


delt haben gehen wir zur optischen Gestaltung über. Davor zeigt die abschlie-
ßende Tabelle alle wichtigen Klassen und deren Funktion.

Klasse Funktion Beispiel


Tk() Fenster window= Tk()

Label Textfeld label = Label(window,text='Python Tkinter Übung')

label.pack(expand=1)

Frame Rahmen frame = Frame(window,relief='ridge',borderwidth=20)

Button Button/Feld button=Button(window,text='Einlesen')

Entry Eingabefeld eingabe=Entry() #Erzeugt ein Eingabefenster

Scrollbar Scrollbar mit Scrollbar = Scrollbar(window)


einer Liste
Listbox listbox=Listbox(window,yscrollcommand=scrollbar.set)

Checkbox Checkbutton check=IntVar() #Check-Variable

checkbutton=Checkbutton(window,

text="Python3",

variable=check,command = einlesen)

6.2. Optische Gestaltung der Fenster


Unsere Intention zur Programmierung von Fenstern war die Schaffung einer be-
nutzerfreundlicheren Umgebung. Mit den erlernten Methoden ist uns das bisher
nur bedingt gelungen. Die Buttons und Fenster erfüllen zwar bereits ihren Zweck,

Grafische Oberflächen erzeugen 105


jedoch lässt die Gestaltung noch zu wünschen übrig. Daher sehen wir uns in die-
sem Unterkapitel einige Möglichkeiten an, um das Layout des Fensters zu opti-
mieren, Bilder anzuzeigen und Texte farbig zu gestalten.

6.3. Der grid-Manager


Python, bzw. tkinter hat für diesen Zweck einen Layout Manager integriert. Un-
ter der Bezeichnung grid kann eine gitterartige Struktur über das Fenster gelegt
werden, welches das Fenster in verschiedene Segmente teilt. Dafür müssen wir
zunächst wissen, in wie viele Zeilen (row) und Spalten (column) unser Fenster
eingeteilt werden soll. Möchten wir das Objekt button in die erste Zeile und erste
Spalte legen, schreiben wir dafür die Anweisung:
button.grid(row=0,column=0) # Index beginnt bei Null

Mit Hilfe des grid-Managers können wir die Anordnung der Elemente, also der
Buttons sowie der Eingabe- oder Textfelder, bestimmen.

Zur optischen Darstellung des Rastersystems erstellen wir uns vier Buttons (but-
ton1 - button4) und ordnen sie mit Hilfe des grid-Befehls an.
from tkinter import* #importiert alle Funktionen des Moduls

window= Tk() #Erstellt das Objekt

button1=Button(window,text='Button1',width=10)

button1.grid(row=0,column=0)

button2=Button(window,text='Button2',width=10)

button2.grid(row=0,column=1)

button3=Button(window,text='Button3',width=10)

button3.grid(row=1,column=0)

button4=Button(window,text='Button4',width=10)

button4.grid(row=1,column=1)

window.mainloop(

Die Buttons werden in insgesamt zwei Reihen und zwei Spalten angelegt.

Wenn wir den grid-Manager verwenden, platziert er die Objekte an die ge-
wünschten Stellen. Damit benötigen wir den pack() Befehl nicht mehr.

Wir dürfen niemals den grid() und pack() Befehl im gleichen Fenster ver-
wenden. Ansonsten wird ein Error angezeigt.

106 Grafische Oberflächen erzeugen


Abbildung 48 Tkinter Darstellung mit Hilfe des grid-Managers

Neben den Angaben zu Spalte und Zeile kann auch festgelegt werden, über wie
viele Spalten und Reihen das Element gelegt werden soll. Die Befehle dafür lau-
ten:
columnspan = 2, rowspan = 2 # Element über zwei Reihen und Spalten platziert

Außerdem können Abstände zwischen zwei Elementen hinzugefügt werden. Mit


den Attributen padx und pady können wir Abstände in X-Richtung und Y-Rich-
tung angeben.

Als Beispiel erweitern wir unsere vier Buttons. Zwischen den Buttons wird ein X-
Abstand von 10 und ein Y-Abstand von 10 eingefügt. Um die passenden Ab-
stände herauszufinden, müssen wir etwas rumprobieren, bis es optisch anspre-
chend ist.

Außerdem werden die Buttons 3 und 4 zusammengefasst zu einem Button, wel-


cher sich über zwei Felder erstreckt. Dafür wird der Button 3 mittig über zwei
Felder gesetzt.
button3.grid(row=1,column=0,columnspan=2,padx=10,pady=10)

Der Code wird somit wie folgt erweitert:


from tkinter import* #importiert alle Funktionen des Moduls

window= Tk() #Erstellt das Objekt

button1=Button(window,text='Button1',width=10)

button1.grid(row=0,column=0,padx=10,pady=10)

button2=Button(window,text='Button2',width=10)

button2.grid(row=0,column=1,padx=10,pady=10)

button3=Button(window,text='Button3',width=10)

button3.grid(row=1,column=0,columnspan=2,padx=10,pady=10)

window.mainloop()

Es ergibt sich ein neues Fenster

Grafische Oberflächen erzeugen 107


Abbildung 49 Erweiterung des grid-Managers

Das sieht doch schon deutlich besser aus als zuvor.

Mit Hilfe der Strukturierung der Elemente können wir ein Fenster deut-
lich benutzerfreundlicher aufbauen.

6.4. Place-Manager
Wir haben die Platzierung von Elementen mit Hilfe eines Rasters besprochen.
Eine noch flexiblere Möglichkeit ist das Platzieren von Objekten mit Hilfe des
Place-Managers. Bei diesem gibt man die konkreten x- und y-Koordinaten an, an
die das Objekt ausgerichtet werden soll. Der Nullpunkt ist dabei die obere, linke
Ecke des Fensters.

Wir nehmen das vorherige Beispiel und realisieren es mit Hilfe des Place-Mana-
gers:
from tkinter import* #importiert alle Funktionen des Moduls

window= Tk() #Erstellt das Objekt

window.geometry('300x100') # H=200, B=500

button1=Button(window,text='Button1',width=10)

button1.place(x=50, y=20)

button2=Button(window,text='Button2',width=10)

button2.place(x=150, y=20)

button3=Button(window,text='Button3',width=10)

button3.place(x=100, y=70)

window.mainloop()

108 Grafische Oberflächen erzeugen


Abbildung 50 Platzierung der Buttons durch den Place-Manager

Das Herausfinden der passenden Koordinaten ist dabei durch mehrfa-


ches Probieren möglich. Daher wird die Einteilung in Zeilen und Spalten
nach Möglichkeit bevorzugt.

Trotzdem hat der Place-Manager seine Vorteile, beispielsweise, wenn bereits


eine Skizze der Benutzeroberfläche mit Maßen (z.B. in cm) vorliegt. In dem Fall
können wir die Abstände direkt in Pixel umrechnen.

Allgemein ist zu erwähnen, dass das Ausrichten an konkrete Koordinaten nicht


nur auf Buttons beschränkt ist. Auch Eingabefelder, Textfelder und sogar Bilder
können so platziert werden. Wie wir Bilder in dem Fenster miteinbeziehen kön-
nen, sehen wir uns als nächstes an.

6.5. Laden von PNG-Dateien


Ein Bild sagt mehr als 1000 Worte. Daher darf die Darstellung von Bildern in einer
benutzerorientierten Programmierung nicht fehlen.

Wenn wir ein Bild anzeigen wollen, muss dieses zunächst als PNG-Datei gespei-
chert werden. Jpg-Dateien sind alternativ auch möglich. Andere Datenformate
werden nur über Umwege unterstützt. Der Pfad der Datei muss dabei bekannt
sein. Für das Beispiel ist das Bild python.png im Pfad
C:\Python_Uebungen\python.png

gespeichert.

Um das Bild zu laden, wird eine variable img angelegt. Ihr wird das Foto überge-
ben. Das ist mittels des Befehls PhotoImage() möglich. Dabei müssen wir file=r
(read) setzen, und den Pfad des zu ladenden Bilds angeben.
img = PhotoImage(file = r"C: \Python_Uebungen\python.png")

Um die Größe des Bildes anzupassen, kann der Befehl

Grafische Oberflächen erzeugen 109


img1 = img.subsample(2,2)

verwendet werden.

Damit wird die Auflösung und somit die Größe des Bildes reduziert.
Wenn wir ein anderes Bild verwenden, muss dieser Befehl entspre-
chend angepasst werden.

Ausprobieren hilft dabei meistens. Für das Beispiel ist der Befehl nicht erforder-
lich. Das Bild ist in der Variablen img1 gespeichert. Um es auf dem Fenster an-
zeigen zu lassen, verwenden wir die Label() Klasse. Ihr übergeben wir die Vari-
able.
label_img=Label(window, image = img)

Label_img.grid()

Anschließend fügen wir die einzelnen Codeteile zu einem Gesamtcode zusam-


men.
from tkinter import *

window = Tk()

window.title("Python ohne Vorkenntnisse")

img = PhotoImage(file = r"C: \Python_Uebungen\python.png")

label=Label(window, image = img)

label.grid()

mainloop()

Abbildung 51 Darstellung eines Bildes über PhotoImage()

Mit dem Importieren von Bildern ist zum ersten Mal wortwörtlich etwas Farbe
in die Darstellung gekommen. Genau dort wollen wir weiter ansetzen, indem wir
Objekte wie Textfelder farbig hervorheben.

110 Grafische Oberflächen erzeugen


6.6. Objekte farbig hervorheben
Bisher haben wir die Anordnung und Darstellung angepasst. Die Felder blieben
bisher grau, lediglich die importierten Bilder wurden farbig angezeigt.

Die Klassen wie beispielsweise die Label() Klasse besitzt bereits Attribute zur
Festlegung der Farbe des Objekts. D.h. ohne nähere Angabe wird standardmäßig
der bekannte Grauton verwendet. Jedoch kann man sowohl die Farbe des Hin-
tergrunds als auch die Farbe der Schrift definieren sowie die Größe und sogar die
Schriftart.

Folgende Attribute müssen wir hierzu festlegen:


Fg –Schriftfarbe : red,green,yellow,pink,…

bg – Hintergrundfarbe: red,green,yellow,pink,…

font – Schriftart und Stil: Normal,Bold,Italic,Roman.. Größe: 12,16,24…

Die Attribute für fg und bg werden als String übergeben. Font benötigt die
Schriftart als string und die Größe als Zahl.
window,text='Groß',fg='white',bg='red',font=('Arial',48)

Als Beispiel werden drei verschiedene Textfelder angelegt, wobei jedes eine an-
dere Hintergrundfarbe, Schriftfarbe, Schriftgröße und Schriftstil erhält.
from tkinter import*

window= Tk() #Erstellt das Objekt

window.title("Python ohne Vorkenntnisse")

#Erstellen der Label

label1 = Label(window,text='Groß',fg='white',bg='red',font=('Arial',48))

label2 = Label(window,text='Mittel',fg='pink',bg='green',font=('Roman',32))

label3 = Label(window,text='Klein',fg='black',bg='yellow',font=('Bold',16))

#Einordnen der Label

label1.grid(row=0,column=0, pady=10)

label2.grid(row=1,column=0,pady=10)

label3.grid(row=2,column=0, pady=10)

window.mainloop()

Das oberste Feld hat einen roten Hintergrund mit weißer Schrift. Die Schriftart
ist Arial und die Schrift ist 48 Punkte groß.

Grafische Oberflächen erzeugen 111


Das zweite Feld hat einen grünen Hintergrund mit pinker Schrift. Die Schriftstil
ist Roman und die Schrift ist 32 Punkte groß.

Das letzte Feld hat einen gelben Hintergrund mit schwarzer Schrift. Die Schriftstil
ist Bold und die Schrift ist 16 Punkte groß.

Abbildung 52 Darstellen von verschiedenen Schriftgrößen, Farben und Schriftarten

Die passenden Attribute, wie beispielsweise die verwendbaren Farben und


Schriftarten, sind unter der offiziellen tkinter-Seite nachzulesen:

https://docs.python.org/3/library/tk.html

Bei vorhandenen Objekten können die Attribute auch ausgelesen oder über-
schrieben werden.

Zum Auslesen eines Attributs wird die Methode cget verwendet. Das Überschrei-
ben eines Wertes erfolgt mit der Methode config.
print(label1.cget('font')) # Font Werte werden ausgelesen und ausgegeben

label1.config(font=('Roman',32)) #Font wird überschrieben

print(label1.cget('font')) # Font Werte werden ausgelesen und ausgegeben

112 Grafische Oberflächen erzeugen


Abbildung 53 Auslesen der Textparameter

Damit haben wir die wichtigsten Bausteine für die Darstellung einer GUI durch-
genommen. In der folgenden Übungsaufgabe wenden wir das Gelernte an, um
eine optisch ansprechende GUI zu erstellen.

6.7. Übung-Taschenrechner
Im Folgenden soll die grafische Darstellung von anhand der Erstellung eines Ta-
schenrechners geübt werden. Die Aufgabenstellung hierfür lautet wie folgt:

1. Erstelle eine Überschrift „Taschenrechner“

2. Erstelle zwei Eingabefelder, in die jeweils eine Zahl eingegeben wird.

3. Erstelle vier Check-Boxen mit den Bezeichnungen plus, minus, mal und geteilt.
Mit der Wahl der Checkbox wird der zu verwendende Operator festgelegt.

4. Erstelle ein Eingabe-/Ausgabefeld für das Ergebnis.

5. Erstelle einen Button, welcher bei Bestätigung das Ergebnis errechnet und in
das Eingabefeld einfügt.

6. optional: Lege für alle Elemente Schriftgrößen, Hintergrundfarben und wei-


tere Attribute fest. Außerdem können Fehleingaben, wenn mehr als eine oder
keine Checkbox ausgewählt wurde, abgefangen werden.

Das Ergebnis könnte dabei wie folgt aussehen:

Grafische Oberflächen erzeugen 113


Abbildung 54 Beispiellösung grafische Darstellung eines Taschenrechners

6.8. Lösung
Zunächst legen wir das Grundgerüst an. Die Bibliotheken werden importiert.
window= Tk() #Erstellt das Objekt

window.geometry('570x280') # H=280, B=570

window.title("Python ohne Vorkenntnisse")

Als nächstes definieren wir die Überschrift label1, unsere vier Checkbuttons 1-4,
die zwei Eingabefelder eingabe1 und eingabe2, unseren Bestätigungs-Button
button1 sowie das Ausgabefeld ausgabe1. Bevor wir die Checkbuttons anlegen
können, müssen wir noch vier Variablen check1-4 erstellen, welche den Inhalt
der jeweiligen Box speichern.
check1=IntVar() #Check-Variable Plus

check2=IntVar() #Check-Variable Minus

check3=IntVar() #Check-Variable Mal

check4=IntVar() #Check-Variable Geteilt

Danach können wir alle Elemente anlegen. Den einzelnen Elementen wurde
gleichzeitig verschiedenen Größen, Hintergrundfarben und Schriftfarben zuge-
ordnet.
label1 = Label(window,text='Taschenrechner',fg='white',bg='grey',font=('Arial',32))

button1=Button(window,text='Rechne',width=10,height=2,command=ausgeben,

fg='white',bg='green',font=('Arial',10))

114 Grafische Oberflächen erzeugen


eingabe1=Entry(fg='black',bg='yellow',font=('Arial',12))

eingabe2=Entry(fg='black',bg='yellow',font=('Arial',12))

ausgabe1=Entry(fg='black',bg='green',font=('Arial',15))

Und die Checkboxen:


checkbutton1=Checkbutton(window,text="Plus",variable=check1)

checkbutton2=Checkbutton(window,text="Minus",variable=check2)

checkbutton3=Checkbutton(window,text="Mal",variable=check3)

checkbutton4=Checkbutton(window,text="Geteilt",variable=check4)

Bei den Checkboxen müssen wir keine Funktion übergeben, da beim An- oder
Abwählen einer Box nichts passieren soll. Lediglich beim Klick auf den button1
soll die Funktion ausgeben() ausgeführt werden.

Die Funktion ausgeben() überprüft zunächst, ob mehr als eine Box aktiviert
wurde. Dazu wird überprüft, ob die Summe aller check-Variablen größer als 1 ist.
Ist das der Fall, wird die Ausgabevariable ausgabe zu 'Mehrere ausgewählt' ge-
setzt.
def ausgeben():

if (check1.get()+check2.get()+check3.get()+check4.get() >1):

ausgabe='Mehrere ausgewählt'

Ist nur eine Checkbox aktiv, werden die Werte in den Eingabefeldern eingelesen.

Da sie als String abgespeichert werden, muss noch eine Typumwandlung in Inte-
ger erfolgen.
else:

zahl1=int(eingabe1.get())

zahl2=int(eingabe2.get())

Im Anschluss werden die einzelnen Fälle abgearbeitet und jede check-Variable


geprüft. Dementsprechend werden die zuvor eingelesenen Daten verrechnet
und in der Ausgabevariablen gespeichert.
if check1.get():

ausgabe = zahl1+zahl2

elif check2.get():

ausgabe = zahl1-zahl2

elif check3.get():

ausgabe = zahl1*zahl2

Grafische Oberflächen erzeugen 115


elif check4.get():

ausgabe = round(zahl1/zahl2,2)

else:

ausgabe='Wähle aus: +, -,*,/'

Bei der Division werden die Zahlen zusätzlich gerundet, da unendlich-periodische


Bruchzahlen auftauchen können.

Falls keine der vier Boxen ausgewählt wurde, wird die Ausgabevariable mit
'Wähle aus: +,-,*,/' überschrieben.

In jedem Fall wird das Ausgabefeld gelöscht und anschließend das Ergebnis (oder
der Fehler) ausgegeben.
ausgabe1.delete(0,'end')

ausgabe1.insert(0,ausgabe)

Als letztes werden alle Objekte platziert. Dafür wurde der grid-Manager verwen-
det. Der place-Manager funktioniert genauso. Der gesamte Programmcode ent-
wickelt sich dabei wie folgt:

from tkinter import* #importiert alle Funktionen des Moduls

def ausgeben():

if (check1.get()+check2.get()+check3.get()+check4.get() >1): #optinale if

ausgabe='Mehrere ausgewählt'

else:

zahl1=int(eingabe1.get()) #Datentyp von string anpassen

zahl2=int(eingabe2.get())

if check1.get():

ausgabe = zahl1+zahl2

elif check2.get():

ausgabe = zahl1-zahl2

elif check3.get():

ausgabe = zahl1*zahl2

elif check4.get():

ausgabe = round(zahl1/zahl2,2)

else:

116 Grafische Oberflächen erzeugen


ausgabe='Wähle aus: +, -,*,/'

ausgabe1.delete(0,'end') # Einrückung beachten, wird immer ausgeführt

ausgabe1.insert(0,ausgabe)

window= Tk() #Erstellt das Objekt

window.geometry('570x280') # H=280, B=570

window.title("Python ohne Vorkenntnisse")

label1 = Label(window,text='Taschenrechner',fg='white',bg='grey',font=('Arial',32))

button1=Button(window,text='Rechne',width=10,height=2,command=ausgeben,

fg='white',bg='green',font=('Arial', 10))

eingabe1=Entry(fg='black',bg='yellow',font=('Arial',12))

eingabe2=Entry(fg='black',bg='yellow',font=('Arial',12))

ausgabe1=Entry(fg='black',bg='green',font=('Arial',15))

'''CHECKFELDER'''

check1=IntVar() #Check-Variable Plus

check2=IntVar() #Check-Variable Minus

check3=IntVar() #Check-Variable Mal

check4=IntVar() #Check-Variable Geteilt

checkbutton1=Checkbutton(window,text="Plus",variable=check1)

checkbutton2=Checkbutton(window,text="Minus",variable=check2)

checkbutton3=Checkbutton(window,text="Mal",variable=check3)

checkbutton4=Checkbutton(window,text="Geteilt",variable=check4)

'''GRID-MANAGER'''

label1.grid(row=0,column=1,padx=10,pady=10,colu mnspan=2)

eingabe1.grid(row=1,column=1,padx=10,pady=10)

eingabe2.grid(row=1,column=2,padx=10,pady=10)

checkbutton1.grid(row=2,column=0,padx=10,pady=10)

checkbutton2.grid(row=2,column=1,padx=10,pady=10)

checkbutton3.grid(row=2,column=2,padx=10,pady=10)

checkbutton4.grid(row=2,column=3,padx=10,pady=10)

button1.grid(row=3,column=1,columnspan=2,pady=10)

ausgabe1.grid(row=4,column=1,columnspan=2,pady=10)

Grafische Oberflächen erzeugen 117


window.mainloop()

Abbildung 55 Reaktionen des Taschenrechners bei verschiedenen Auswahlmöglichkeiten

Das war nicht nur das Ende der Übung, sondern auch dieses Buches – fast! Denn
ein Kapitel, welches immer mehr an Bedeutung gewinnt, soll nicht unerwähnt
bleiben. Es zeigt die Möglichkeiten, die mit Python einfach zu realisieren sind.
Die Rede ist von künstlicher Intelligenz und neuronalen Netzen. Die meisten Un-
ternehmen verwenden Python bereits als Industriestandard für neuronale Netze
und machine learning.

118 Grafische Oberflächen erzeugen


7. Künstliche Intelligenz und neuronale Netze
Eines der Themen, welches seit Jahren in aller Munde ist, ist die künstliche In-
telligenz, kurz KI. In Verbindung mit dem Schlagwort KI werden oftmals Begriffe
wie neuronale Netze, maschinelles Lernen (machine learning) oder deep lear-
ning in den Raum geworfen.

Es macht daher Sinn, zunächst die verschiedenen Begrifflichkeiten zu erklären.

Künstliche Intelligenz, oftmals auch Artificial Intelligence (AI) genannt,


ist der Überbegriff, unter dem alle anderen Begriffe zusammengefasst
werden. KI bezeichnet das Nachahmen oder Simulieren von menschli-
cher Intelligenz mittels Maschinen, heutzutage fast ausnahmslos Com-
putern bzw. ganzen Computersystemen.

Dazu werden spezielle Abläufe von Funktionen verwendet. Diese Funktions-


Strukturen werden Algorithmen genannt.

Künstliche Intelligenz verwendet Computer-Algorithmen, welche sich


selbst anpassen und verbessern.

Der Begriff neuronale Netze bezeichnet hingegen eine Art, wie die lernenden Al-
gorithmen aufgebaut sind. Maschinelles Lernen, machine learning, deep learn-
ing etc. beschreibt der Vorgang des Verbesserns eines neuronalen Netzes, also
das stetige Anpassen des Netzes: Das Netz „lernt“.

Bevor wir zum Aufbau eines neuronalen Netzes kommen, sehen wir uns zunächst
an, worin die Vorteile bei der Anwendung von künstlicher Intelligenz liegen.

Das Ziel der folgenden Kapitel ist es nicht, das Konstrukt der künstlichen Intelli-
genz bis ins kleinste Detail verstanden zu haben. Das würde den Rahmen dieses
Buches mehr als sprengen. Stattdessen werden die grundlegenden Prinzipien er-
klärt und Beispiele in Python behandelt, sodass man sich bei Interesse detaillier-
ter mit dem Themengebiet auseinandersetzen kann.

7.1. Ziel und Nutzen einer KI


Bevor wir eine KI programmieren, klären wir erst einmal die Frage, wofür KIs
überhaupt sinnvoll sind.

KIs verwerten riesige Datenmengen und finden Zusammenhänge her-


aus, welche Faktoren Einfluss auf ein Ergebnis haben. Sie können an-
hand vergangener Daten Prognosen für die Zukunft ausgeben.

Künstliche Intelligenz und neuronale Netze 119


Als Beispiel nehmen wir den Aktien-Markt. Aktien von Unternehmen sind sehr
volatil, das bedeutet, der Preis steigt und fällt stetig. Selbst Experten, die ihr gan-
zes Leben damit verbringen, die Mechanismen hinter den Aktienkursen zu un-
tersuchen, haben es nicht geschafft, den Aktienkurs eines Unternehmens zuver-
lässig vorherzusagen. Denn für den Kurs einer Aktie spielen viele Faktoren eine
Rolle: Die Gewinne der Unternehmen, die Erwartungen der Leute, welche die
Aktie kaufen oder auch politische und geografische Auseinandersetzungen von
Staaten.

Die genauen Faktoren kennt niemand zu 100%, es könnte theoretisch auch sein,
dass eine Aktie bei gutem Wetter eher steigt als fällt. Das hört sich abwegig an,
aber es existieren zahlreiche Faktoren, die einen potenziellen Einfluss auf den
Kurs einer Aktie haben könnten.

Diese Menge an Einflüssen kann ein einfacher Mensch nicht überschauen. Und
genau hier könnte eine KI zum Einsatz kommen.

Eine KI kann anhand existierender Daten Zusammenhänge erkennen und zukünf-


tige Ereignisse berechnen. Beispielsweise analysiert eine KI das Verhalten aller
Käufer und Verkäufer, politische Zusammenhänge und vieles mehr. Schlussend-
lich gibt es am Ende eine Vorhersage zur Entwicklung der Aktie ab. Je mehr Daten
die KI hat und je länger sie trainiert wurde, umso genauer ist die Prognose. Mo-
mentan ist es noch keiner KI gelungen, die Aktienkurse zuverlässig vorherzusa-
gen.

Würden wir einer KI alle Daten, die es jemals gegeben hat, einspeisen
und würden wir sie unendlich lange trainieren, würde die KI alles vor-
hersagen können, was jemals passieren wird. Sie wäre allwissend. Sie
könnte die Aktienkurse vorhersagen, wann und wo ein Mensch geboren
wird oder wie lange wir alle noch leben werden.

Zugegeben, das ist ein absurdes


Beispiel, welches wohl niemals real
werden wird. So viele Daten könnte
ein Computer niemals verarbeiten
und das Trainieren würde unend-
lich lange dauern. Anhand des Bei-
spiels sehen wir jedoch, wohin die
Reise geht. Immer mehr Informati-
onen, immer mehr Rechenleistung.
Nicht umsonst sammeln Google,
Amazon und Co immer mehr Be-
nutzerdaten und bauen ihre Re-
chenzentren weiter aus.
Abbildung 56 Gang eines Serverraums mit hunderten Computern

120 Künstliche Intelligenz und neuronale Netze


Der Gedanke einer alleswissenden, künstlichen Intelligenz erscheint auf den ers-
ten Moment etwas beängstigend, dabei sollten wir nicht nur das Negative sehen.
KI ist eine Chance. Wir könnten Durchbrüche in der Wissenschaft erlangen, au-
tonomes Fahren steht in den Startlöchern und vielleicht findet der nächste Su-
per-Computer ein Heilmittel gegen Krebs. Auf jeden Fall ist die künstliche Intelli-
genz ein Themengebiet, bei dem viel Potenzial vorhanden ist. Es rentiert sich,
sich mit damit auseinanderzusetzen.

Wir wissen nun also, wozu eine KI fähig ist und welche Vorteile sie bietet. Sehen
wir uns nun an, wie eine KI bzw. ein neuronales Netz aufgebaut ist.

7.2. Aufbau eines neuronalen Netzes


Das Vorbild für den Aufbau der neuronalen Netze bietet der leistungsstärkste
Rechner überhaupt – unser Gehirn! Das menschliche Gehirn ist deutlich effizien-
ter als jeder jemals entwickelte Computer. Es besteht aus einzelnen Neuronen,
die durch Synapsen komplex miteinander verschaltet sind.

Abbildung 57 Vernetztes Gehirn

Ein künstliches, neuronales Netz ist nach diesem Vorbild aufgebaut. Es werden
verschiedene Neuronen erstellt, welche lernen, wie sie miteinander verknüpft
werden müssen, um das optimale Ergebnis zu einer definierten Aufgabe zu
finden. Das Erstellen dieser Verknüpfungen benötigt Daten, Zeit und
Rechenleistung.

Ein Neuron wird dabei auch als Tensor bezeichnet. Die Neuronen sind in
verschiedenen Ebenen (layer) aufgebaut.

Künstliche Intelligenz und neuronale Netze 121


Abbildung 58 3 Schichtenaufbau eines neuronalen Netzes

Dabei besitzt ein neuronales Netz normalerweise mindestens drei Schichten. In


der ersten Schicht werden die Daten eingegeben (input layer). In der zweiten bis
zur vorletzen Stufe werden die Daten verarbeitet und kombiniert (hidden layer)
und in der letzten schließlich ausgegeben (output layer). Wie in der Zeichnung
zu sehen ist, haben alle Neuronen Verbindung zu den anderen. Die
Verbindungen zwischen den Neuronen werden in Anlehnung an das menschliche
Gehirn Synapsen genannt.

Es gibt viele weitere Möglichkeiten, ein neuronales Netz aufzuspannen.

Eine davon ist, dass nicht nur die vorherigen Neuronen einen Einfluss auf die
nächste Schicht haben, sondern dass die einzelnen Neuronen sich selbst
beeinflussen können. Für das generelle Verständnis sind die konkrete
Ausführung und der Aufbau der verschiedenen Strukturen irrelevant. Die
Prinzipien lassen sich auf alle Strukturen anwenden.

7.3. Wie lernt ein neuronales Netz?


Ein neuronales Netz hat den Vorteil, dass es mit zunehmender Zeit immer ge-
nauer wird. Je mehr Daten ihm zugeführt werden, umso effektiver und umso
effizienter wird das Netz.

Der bereits erwähnte Begriff „trainieren“ bezeichnet das Durchlaufenlassen von


Zyklen und das Verbessern der Verbindungen der Neuronen. Die Durchläufe
werden auch als Zyklen bezeichnet.

122 Künstliche Intelligenz und neuronale Netze


Aber wie sieht dieses Training konkret aus? Dafür müssen wir zunächst verste-
hen, dass eine KI anfangs keinerlei interne Inhalte und Daten besitzt. Als Beispiel
nehmen wir zwei Datenreihen.
eingang=[1,2,3,4,5]

ausgang=[3,6,9,12,15]

Der Zusammenhang zwischen den beiden Reihen dürfte jedem auf Anhieb klar
sein. Jedes Element der zweiten Reihe ist das Dreifache des passenden Elements
der ersten Reihe. Eine KI weiß das zu Beginn jedoch nicht.

1. Durchlauf
„Raten“

1 Neuronales Netz 5

Anpassen der Abgleich mit Er-


Parameter des gebnis „3“
Netzes Fehler = 2

Abbildung 59 Erster Trainingsdurchlauf einer KI

Die KI versucht, zunächst zufällig Zusammenhänge zwischen den Datensätzen zu


finden. Dafür nimmt sie ein Element aus der Eingabe-Datenreihe und prognosti-
ziert für diesen Wert einen Ausgabewert. Anschließend gleicht die KI das berech-
nete Ergebnis mit dem richtigen Ergebnis aus der Ausgabe-Liste ab und passt ihre
Verknüpfungen an, sodass das Ergebnis beim nächsten Durchlauf näher am ge-
wünschten Ergebnis liegt. Das wird für alle Daten aus den Datensätzen probiert,
sodass am Ende insgesamt alle errechneten Daten möglichst nahe am Ausgabe-
Datensatz liegen.

Künstliche Intelligenz und neuronale Netze 123


2. Durchlauf
„Raten“

1 Neuronales Netz 1

Fehler kleiner? Abgleich mit Er-


gebnis „3“
Ja – Anpassen Fehler = 2
Nein – Änderung ver-
werfen

Abbildung 60 Zweiter Trainingsdurchlauf einer KI

Dabei werden zunächst auch unsinnige, zufällige Verbindungen gebildet, die spä-
ter wieder aufgelöst werden. Nach und nach bilden sich Verknüpfungen, die im-
mer näher an das gewünschte Ergebnis herankommen. Mit jedem neuen Durch-
lauf wird das Ergebnis genauer und nähert sich den richtigen Werten an.

Dadurch bilden sich interne Verschaltungen, die immer akkurater werden.

In einem realen neuronalen Netz wird nicht, wie in der Abbildung, jede
Zahl einzeln durchlaufen, sondern immer alle Zahlen gleichzeitig, um
Quer-Abhängigkeiten miteinzubeziehen. In unserem Beispiel wäre das
die Prüfung, ob die anderen Daten der Datenreihe, beispielsweise die
Zahlen [2,3,4,5], ebenfalls einen Einfluss auf das Ergebnis 2 haben.

Wenn wir, nachdem das Netz trainiert wurde, neue, bisher unbekannte Daten
einspeisen, beispielsweise die Zahl 10, muss das Netz die passende Antwort auf
diese Zahl selbst errechnen.

Das Netz wird durch die bereits bekannten Daten eine Näherung des Ergebnisses
ermitteln, bei uns wäre das optimalerweise die Zahl 30. In der Praxis wird das
Ergebnis etwas davon abweichen, wobei die Abweichung mit der Anzahl der
Durchläufe immer geringer wird.

Prinzipiell ist somit bereits der Aufbau einer künstlichen Intelligenz erklärt. Es
wird ein neuronales Netz aus mehreren Schichten und vielen Neuronen aufge-
spannt. Anschließend müssen dem Netz Daten eingespeist werden. Durch das
Trainieren verbessert das Netz die internen Verbindungen und nähert das Ergeb-
nis für zukünftige Werte immer weiter dem wahren Wert an.

Natürlich zeigt das Beispiel die einfachste Form eines neuronalen Netzes mit nur
einer Eingangs- und einer Ausgangsliste. In der Realität sind die Daten komplex,

124 Künstliche Intelligenz und neuronale Netze


sodass man sie meistens nicht mehr vollständig überblickt. Die internen Zu-
stände der Neuronen und deren Ursprünge sind in den meisten Fällen auch nicht
mehr nachvollziehbar.

Als nächstes sehen wir uns die Realisierung in Python an. Dafür verwenden wir
bestehende Module.

7.4. Datenstromoptimierte Programmierung


Python gewinnt immer mehr an Beliebtheit. Ein Aspekt ist die objektorientierte
Programmierung OOP. Ein anderer Aspekt ist die leichte Programmierung von
neuronalen Netzen.

Da neuronale Netze intern Daten verarbeiten und die Daten schritt-


weise in den verschiedenen Schichten verändert und anschließend an
die nächste Schicht weitergegeben werden, spricht man auch von da-
tenstromoptimierter Programmierung.

Durch einfaches Verwenden von bestehenden Bibliotheken können wir inner-


halb kürzester Zeit ein neuronales Netz anlegen. Die dazu benötigte Bibliothek
ist die tensorflow Bibliothek.

Die Bibliothek tensorflow ist von Google gestaltet worden. Im Vergleich zu einer
privaten Bibliothek hat Google als Großkonzern quasi unbegrenzte finanzielle
Mittel. Die Bibliothek wurden von professionellen Entwicklern erstellt. Ten-
sorflow ist sehr zuverlässig und wird regelmäßig auf dem Laufenden gehalten. In
der open source deep-learning Bibliothek Keras, einer auf tensorflow aufbau-
enden Unterbibliothek, sind die Funktionen aufgeführt, welche wir zum Aufbau
eines neuronalen Netzes benötigen.

Keras kann auch unabhängig von tensorflow importiert werden. Bei Keras han-
delt es sich um eine private Bibliothek.

Die Bibliotheken sind nicht im Python Interpreter installiert. Daher müssen wir
die gewünschte Bibliothek zunächst installieren und den folgenden Befehl direkt
in die Konsole eingeben.
pip install keras

pip install tensorflow

Falls der Befehl nicht funktionieren sollte, kann alternativ der Befehl
conda install -c conda keras

conda install -c conda tensorflow

Künstliche Intelligenz und neuronale Netze 125


verwendet werden. Eine genauere Installationsanleitung ist unter
https://github.com/keras-team/keras zu finden.

Windows Nutzer müssen gegebenenfalls das Programm „Anaconda Prompt“


starten. Dazu müssen wir Anaconda Prompt im Startverzeichnis oder in der
Windows-Suchleiste suchen.

Anschließend wird die Eingabe mit Enter bestätigt. Gegebenenfalls müssen wir
davor und danach das Programm Spyder neu starten.

Es werden automatisch die Bibliotheken keras und tensorflow sowie weitere in-
stalliert.

Abbildung 61 Installation der benötigten Bibliotheken

Nach der Installation der Bibliotheken können wir die beiden wie gewohnt im-
portieren. Damit wir nicht jedes Mal den vollständigen Modulnamen tensorflow
bzw. keras angeben müssen, importieren wir alle Funktionen
from tensorflow import*

from keras import*

Als nächstes legen wir ein neuronales Netz an.

Dafür wird der Befehl models.Sequential() aus der Keras-Bibliothek verwendet.


Das neuronale Netz könnten wir beispielsweise mit netz1 oder neuro_netz be-
nennen.

126 Künstliche Intelligenz und neuronale Netze


In Keras hat sich durchgesetzt, ein neuronales Netz als model zu bezeichnen. Da
viele Hilfsseiten und Beispieltexte dieselbe Bezeichnung verwenden, bleiben wir
einheitlich bei der Bezeichnung.
model = models.Sequential()

Damit haben wir unser erstes neuronales Netz erstellt. Dieses beinhaltet noch
keine Schichten und keine Neuronen. Das Netz ist das Grundgerüst, in das wir
Schichten und Neuronen einfügen können. Bevor wir die Schichten und Neuro-
nen anlegen, müssen wir zunächst wissen, wie viele Input-Neuronen wir benöti-
gen. Wir erinnern uns, dass die Input-Schicht die allererste Schicht bildet, die die
Eingangsdaten aufnimmt.

Um die Input-Größe zu bestimmen, nehmen wir unsere beiden Datensätze zur


Hilfe.
eingang=[1,2,3,4,5]

ausgang=[3,6,9,12,15]

Die Datensätze bestehen aus 5 Elementen. Bei der Anzahl der Neuronen
kommt es jedoch nicht auf die Anzahl, sondern auf die Dimension der
Daten an! In unserem Fall dürfen der Eingang der ersten Schicht sowie
der Ausgang der letzten Schicht lediglich ein Neuron beinhalten!

Die Dimension einer Liste ist immer 1! Streng genommen arbeiten die
Layer nicht mit Listen, sondern mit Arrays. Die Listen werden dabei in
ein eindimensionales Array überführt. Später lernen wir noch Arrays
und neuronale Netze mit mehr als einem Eingangsneuron kennen.

Als erstes legen wir den ersten Layer, den Input-Layer, an.

Dafür werden der add() Befehl sowie die layer() Funktion verwendet.
#Input-Layer

model.add(layers.Dense(units=3,input_shape=[1]))

Durch den Befehl wird dem Netz ein Layer vom Typ Dense hinzugefügt. Dense
steht für ein dichten Layer. Das bedeutet, dass jedes Neuron innerhalb des Lay-
ers mit jedem Neuron des nächsten Layers verknüpft ist, und nicht beispiels-
weise mit nur jedem zweiten. Außerdem geben wir die Anzahl an Neuronen
(units) an, in unserem Fall wählen wir drei Neuronen.

Input_shape enthält, wie bereits erwähnt, die Dimension unserer Eingangsliste.

Als nächstes legen wir einen weiteren Layer an. Wir wählen zwei Neuronen.
#Zwischenlayer

model.add(layers.Dense(units=2))

Künstliche Intelligenz und neuronale Netze 127


Die Layer verknüpfen sich automatisch mit den vorherigen. Der letzte Layer darf
dabei nur ein Neuron enthalten, da dieses den Output-Layer bildet und unsere
Ausgangsliste die Dimension eins besitzt.
#Outputlayer units muss 1 sein

model.add(layers.Dense(units=1))

Damit haben wir die Struktur unseres Netzes aufgebaut.

Als letztes müssen wir unser neuronales Netz noch compilen. Das ist ein zusätz-
licher, erforderlicher Schritt. Der compile()-Funktion muss eine loss-Funktion
hinzugefügt werden.

Die loss Funktion gibt an, wann eine Abweichung als „gut“ oder „schlecht“ be-
trachtet werden soll. Als Schätzungsmethode verwenden wir die Annahme, dass
der mittlere quadratische Fehler (eng. mean square error) kleinstmöglich wer-
den soll.

Das bedeutet, ein Wert wird als „gut“ bezeichnet, wenn die Abwei-
chung vom Mittelwert zum Quadrat minimal wird. Der mittlere quadra-
tische Fehler wird sehr häufig in der Datenverarbeitung angewandt und
ist eine anerkannte Schätzmethode der mathematischen Statistik. Er
gewichtet Ausreißer aus einer Messreihe weniger stark als andere
Schätzmethoden.

Neben dem Gütekriterium für das Schätzen des Fehlers benötigt der compiler
noch einen optimizer. Dem optimizer übergeben wir eine Optimierungsme-
thode, standardmäßig verwenden wir hier SGD (stochastic gradiant decent). Die
genaue Wirkungsweise eines Optimizers ist für uns dabei unwichtig. Wir müssen
lediglich wissen, dass es verschiedene Optimierungsverfahren gibt.
model.compile(loss='mean_squared_error',optimizer='sgd')

Damit ist das neuronale Netz compliliert und bereit, trainiert zu werden. Dafür
übergeben wir dem Netz unsere beiden Datensätze mit Hilfe der fit-Funktion.
Der Input, welcher unsere Liste eingang bildet, wird als x, die Ausgangsliste aus-
gang als y bezeichnet.

Außerdem benötigen wir noch die Anzahl an Trainingsdurchläufen, welche wir


der Variablen epochs übergeben.
model.fit(x=eingang,y=ausgang,epochs=1000)

Jetzt können wir das Netz das erste Mal laufen lassen. In der Konsole werden die
Durchläufe in wahnsinniger Geschwindigkeit angezeigt. Nach einigen Sekunden
sollten alle 1000 Durchläufe geschafft sein. Am Ende jeder Zeile können wir den
loss-Wert sehen. Dieser ist am Anfang noch sehr groß und strebt mit der Anzahl
der Durchläufe gegen Null.

128 Künstliche Intelligenz und neuronale Netze


Abbildung 62 Konsolenausgabe bei 1000 Durchläufen

Als letztes wollen wir unser trainiertes Netz verwenden, um Zahlen vorherzusa-
gen. Dazu verwenden wir den predict()-Befehl und übergeben ihm jeweils eine
Zahl, im Beispiel rufen wir drei predict()-Befehle mit den Zahlen 6, 7 und 8 auf.
print(model.predict([6]))

print(model.predict([7]))

print(model.predict([8]))

Bevor wie das Programm starten, sehen wir uns den gesamten Code an.
from keras import*

model=Sequential()

#Input-Layer input muss 1 sein

model.add(layers.Dense(units=3,input_shape=[1]))

#Zwischenlayer

model.add(layers.Dense(units=2,input_shape=[1]))

#Outputlayer units muss 1 sein

model.add(layers.Dense(units=1,input_shape=[1]))

eingang=[1,2,3,4,5]

ausgang=[3,6,9,12,15]

Künstliche Intelligenz und neuronale Netze 129


#Erstellen des Netzes ("adam"alterntiv zu "sgd")

model.compile(loss='mean_squared_error',optimizer='sgd')

#Trainieren des Netzes 1000 Durchläufe

model.fit(x=eingang,y=ausgang,epochs=1000)

#Vorhersagen der Zahlen

print(model.predict([6]))

print(model.predict([7]))

print(model.predict([8]))

Anschließend starten wir das Programm. Das neuronale Netz wird trainiert und
nach kurzer Zeit werden die vorherzusehenden Daten ausgeben.

Abbildung 63 Konsolenausgabe der geschätzten Werte

Die gewünschten Zahlen waren bei uns 18, 21 und 24. Wir sehen also, dass das
neuronale Netz noch deutlich besser werden muss.

Das neuronale Netz wird genauer, indem wir ihm mehr Daten zur Ver-
fügung stellen oder es öfters durchlaufen lassen.

Erhöhen wir beispielsweise die Anzahl an Durchläufen von 1000 auf 10.000, wird
das Ergebnis schon deutlich genauer. Auch der Loss-Wert wird noch einmal er-
kennbar kleiner.

Abbildung 64 Verbesserung der Schätzwerte durch höhere Zyklenanzahl

130 Künstliche Intelligenz und neuronale Netze


Je nach Leistung des Computers oder Laptops können 10.000 Durch-
läufe den Computer fordern und sehr lange dauern. Das Programm
kann dabei jederzeit durch den roten Knopf in der oberen rechten Ecke
der Konsole abgebrochen werden.

Es empfiehlt sich, mit den Parametern herumzuspielen. Ab wie vielen Durchläu-


fen verbessert sich das Ergebnis fast nicht mehr? Haben weitere Schichten oder
mehr Neuronen einen positiven oder negativen Einfluss? Was passiert bei ande-
ren Datenreihen?

Wenn der loss-Wert oder das Ergebnis „nan (Not a Number)“ anzeigt,
liegt ein numerischer Fehler vor. Das kann bei neuronalen Netzen rela-
tiv schnell passieren. Es gibt keine einheitliche Lösung für diesen Fehler.
In diesem Fall sollten alle Schritte, die zu diesem Fehler führen, rück-
gängig gemacht werden.

Auch das Angeben eines anderen Optimizer-Verfahrens (sgd) kann Abhilfe schaf-
fen. Eine Alternative wäre beispielsweise optimizer=‘adam‘

Als nächstes werden wir etwas komplexere Daten verarbeiten. Dafür müssen wir
zunächst verstehen, dass das neuronale Netz in Python Arrays verarbeitet und
keine Listen.

7.5. Arrays und numpy


Arrays sind ein mathematisches Konstrukt, um mit mehrdimensionalen Variab-
len zu rechnen. In der Mathematik werden diese Arrays auch Matrizen (Einzahl
Matrix) genannt. In Python ist der Begriff Array, genau wie Listen, ein eigener
Datentyp. Matrizen sind den mehrdimensionalen Listen sehr ähnlich. Jedoch be-
sitzen Listen nur einen Index.

Eine mehrdimensionale Liste besitzt als Element dieses Index wiederum


eine eigene Liste. Ein Array hingegen besitzt zwei Indizes (bei einem
zwei-dimensionalen Array).

In Spyder können wir die Unterschiede sehr gut darstellen. Dazu importieren wir
die Bibliothek numpy, die viele numerischen Funktionen enthält. Darunter sind
bekannte Funktionen wie die Expotentialfunktion, Logarithmen oder Sinus- und
Cosinusfunktionen. Numpy gehört zu den Standardbibliotheken, die im Interpre-
ter eingebunden sind. Daher müssen wir numpy lediglich importieren. Da wir nur
die array()-Funktion benötigen, wird nur diese importiert.
from numpy import array

Als nächstes schauen wir uns den konkreten Unterschied zwischen mehrdimen-
sionalen Listen und Arrays an. Dazu legen wir einen Datensatz an, welcher das

Künstliche Intelligenz und neuronale Netze 131


Gehalt eines Arbeiters, in Abhängigkeit vom Alter, Geschlecht und anderen Fak-
toren abbildet. Mit Hilfe dieser Tabelle und einem neuronalen Netz wollen wir
anschließend das Gehalt für eine beliebige Person abschätzen.

Alter Dauer der Berufserfah- Geschlecht Monatliches


Ausbildung rung in Jahren 0=Mann Gehalt in €
in Jahren 1= Frau
18 2 0 0 2100

32 4 10 0 3400

44 2 20 0 3200

60 6 34 0 5500

20 2 2 1 2300

24 4 0 1 2700

44 5 21 1 3200

52 2 32 1 3200

Die Tabelle beinhaltet lediglich Stichproben. Außerdem sind wichtige


Faktoren wie das Berufsfeld nicht vertreten! Als Beispiel sind die Daten
dennoch bestens geeignet. In der Realität können wir schließlich auch
nur Stichproben erforschen.

Wir legen in Python die Daten zunächst als zweidimensionale Liste an.
datensatz1=[

[18, 2, 0, 0, 2100],

[32, 4, 10, 0, 3400],

[44, 2, 20, 0, 3200],

[60, 6, 34, 0, 5500],

[20, 2, 2, 1, 2300],

[24, 4, 0, 1, 2700],

[44, 5, 21, 1, 3200],

[52, 2, 32, 1, 3200]

Als nächstes verwenden wir die Funktion array(), um aus der Liste ein Array zu
formen.

132 Künstliche Intelligenz und neuronale Netze


data_array=array(datensatz1)

In Spyder öffnen wir den Variablen-Explorer.

Abbildung 65 Datentypenanzeige im Variablen Explorer von Spyder

Wir sehen die verschiedenen Datentypen Array of int32 (Integer mit 32 Bit) und
list. Noch anschaulicher wird der Unterschied, wenn wir auf die Variable daten-
satz sowie auf die Variable data_array klicken und diese damit öffnen.

Abbildung 66 Liste mit 8 Elementen (jeweils eine Liste mit 5 Elementen)

Abbildung 67 Array mit 8x5 Elementen

Künstliche Intelligenz und neuronale Netze 133


Die Daten der beiden Datentypen sind identisch. Ein Array hingegen besitzt zwei
Indizes, während eine Liste lediglich einen Index enthält, der auf eine komplette
Liste verweist.

Für uns ist es wichtig zu verstehen, dass neuronale Netze mit Arrays ar-
beiten und wir daher unsere Listen in Arrays umwandeln müssen.

Als nächstes legen wir den Datensatz an und erstellen eine Eingangsvariable und
eine Ausgabevariable. Die Eingangsvariable enthält alle Daten, die Ausgabevari-
able das Gehalt der Person.
eingang=data_array[0:8,0:4] #Alle Zeilen (Index 0-7) Spalte 0-3

ausgang=data_array[0:8,4] #Alle Zeilen Spalte 4

Wir geben in eckige Klammern unsere gewünschten Zeilen und unsere ge-
wünschten Spalten an, jeweils mit einem Komma als Trennzeichen. Mit Hilfe der
Doppelpunkte werden alle Elemente ausschließlich des Indexes verwendet.

Die Dimension unseres Eingangsvektors ist vier (4 Elemente pro Zeile)


und die Dimension des Ausgangsvektors ist eins (nur ein Element pro
Person, nämlich das Gehalt).

Dementsprechend legen wir unser neuronales Netz an.

Diesmal erstellen wir insgesamt vier Layer: einen Input- und einen Output-Layer
sowie zwei Zwischenlayer. Außerdem weisen wir diesmal deutlich mehr Neuro-
nen pro Layer zu: 16 für die Eingangsschicht, 64 für die mittleren Schichten und
eines für die Ausgangsschicht.
model=Sequential()

#Input-Layer input muss 4 sein

model.add(layers.Dense(units=16,input_shape=[4]))

#Zwischenlayer

model.add(layers.Dense(units=64))

model.add(layers.Dense(units=64))

#Outputlayer units muss 1 sein

model.add(layers.Dense(units=1))

Als nächstes compilieren wir das Netz und trainieren es anschließend. Diesmal
wird der Optimizer adam verwendet. Außerdem wurden die Zyklen auf 5000 er-
höht. Je nach Rechenleistung kann das Trainieren entsprechend einige Minuten
dauern.

134 Künstliche Intelligenz und neuronale Netze


#Compilen des Netzes

model.compile(loss='mean_squared_error',optimizer= 'adam')

#Trainieren des Netzes mit 5000 Durchläufe n

model.fit(x=eingang,y=ausgang,epochs=5000)

Als letztes kommt der spannende Teil. Wir wollen das Gehalt einer Person ab-
schätzen, welche nicht im Datensatz vorkommt.

Dazu legen wir uns zwei Testpersonen, pers1 und pers2, an.

Tom ist männlich, 18 Jahre alt, hat eine einjährige Ausbildung und entsprechend
ein Jahr Berufserfahrung.

Lisa ist weiblich, 52 Jahre alt, hat eine siebenjährige Ausbildung und bereits 20
Jahre Berufserfahrung.
#Vorhersagen der Zahlen

tom=array([[18,1,1,0]])

lisa=array([[52,7,20,1]])

print(model.predict(tom))

print(model.predict( lisa))

Wenn wir das Programm starten, wird das Netz trainiert. Als Ergebnis erhalten
wir anschließend:

Abbildung 68 Geschätztes Gehalt von Tom und Lisa

Das geschätzte monatliche Gehalt für Tim beträgt 1920€ und für Lisa 4838 €.

Unser neuronales Netz hat die vier Faktoren ausgewertet und anhand
dieser Daten ein potenzielles Gehalt abgeschätzt.

Die KI kann auch die einzelnen Einflüsse der Eingangsdaten bewerten.

Ist anhand des Datensatzes eine ungleiche Bezahlung aufgrund des Geschlechts
festzustellen? Um diese These zu prüfen, erstellen wir wiederum zwei Personen,
Niklas und Jennifer. Beide sind 30 Jahre alt, haben eine dreijährige Berufsausbil-
dung und sieben Jahre Berufserfahrung. Der einzige Unterschied, den wir in den
Daten setzen, ist das Geschlecht.

Künstliche Intelligenz und neuronale Netze 135


niklas=array([[30,3,7,0]])

jennifer=array([[30,3,7,1]])

print(model.predict(niklas))

print(model.predict(jennifer))

Wiederum lassen wir das neuronale Netz durchlaufen und erhalten ein monatli-
ches Gehalt für Niklas von 3059 € und für Jennifer von 2570 €.

Abbildung 69 Abhängigkeit des Geschlechts vom geschätzten Gehalt

Der Zusammenhang, dass sich das Geschlecht auf das Gehalt auswirkt, kann
ohne Zweifel reproduziert werden. Anhand der Messdaten war das nicht eindeu-
tig nachzuweisen.

Es können auch andere Einflussgrößen wie unterschiedliches Alter, Be-


rufserfahrung etc. getestet werden.

Dabei müssen wir immer im Hinterkopf behalten, dass alle Schätzungen lediglich
auf Basis der Stichproben getroffen werden. Vielleicht hatten wir zufälligerweise
nicht-repräsentative Stichproben herausgesucht.

Um eine zuverlässige Aussage treffen zu können, benötigen wir deutlich


mehr Daten.

„Daten sind das neue Öl“


EU-Politikerin Meglena Kuneva - 2009

Damit beenden wir den Einblick in die Welt der neuronalen Netze. Wir haben
gelernt, wie ein neuronales Netz aufgebaut ist und wie man ein einfaches, neu-
ronales Netz in Python programmiert. Außerdem haben wir gesehen, dass die
Genauigkeit erheblich vom Rechenaufwand und von den eingespeisten Daten
abhängt.

Zusammenfassend haben wir alle essenziellen Teile der Python-Programmierung


bearbeitet. Wir haben uns durch die Grundlagen gearbeitet, haben Klassen und
Objekte kennengelernt und sogar künstliche Intelligenz angeschnitten.

Natürlich ist das Python-Universum noch deutlich umfangreicher und es gibt un-
zählige Module, Schnittstellen zu anderen Programmen und vieles mehr. Auf je-
den Fall sollte jetzt, nach der Lektüre dieses Buchs, mehr als der Grundstein ge-
legt sein. In diesem Sinne: Gutes Programmieren!

136 Künstliche Intelligenz und neuronale Netze


Künstliche Intelligenz und neuronale Netze 137
Gratis eBook
Danke, dass du dir dieses Buch gekauft hast. Da der Druck des Buchs direkt von
Amazon übernommen wird und ich keinen Einfluss auf die Qualität der Bilder
habe, kann es sein, dass vereinzelt Details verloren gehen.

Deshalb biete ich beim Kauf des Buches das eBook gratis als PDF-Datei an. Dort
sind alle Bilder hochauflösend und man erhält immer die aktuelle Version.

Dazu schicke eine Nachricht mit dem Betreff „Python3-eBook“, sowie einen
Screenshot des Kaufs oder einen Nachweis über die Bestellung bei Amazon an
die E-Mail:

BenjaminSpahic@pbd-verlag.de

Ich werde dir das eBook und die Programmcodes umgehend zukommen lassen.

Wenn dir etwas fehlt, nicht gefallen hat oder du Verbesserungsvorschläge oder
Fragen hast, schreib mir gerne eine E-Mail.

Konstruktive Kritik ist wichtig, um etwas verbessern zu können. Ich überarbeite


das Buch stetig und gehe gern auf jeden konstruktiven Verbesserungsvorschlag
ein.

Ansonsten, wenn dir das Buch gefallen hat, würde ich mich auch über eine posi-
tive Bewertung bei Amazon freuen. Das hilft der Sichtbarkeit des Buchs und ist
das größte Lob, welches ein Autor bekommen kann.

Dein Benjamin

Über den Autor


Benjamin Spahic wurde 1995 in Heidelberg Wie sieht der Alltag eines Autors aus?
geboren und wuchs in einem 8.000-Seelen- Jetzt auf Instagram folgen!
Dorf in der Nähe von Karlsruhe auf. Seine Lei-
denschaft zur Technik spiegelt sich, nach dem
Absolvieren des allgemeinbildenden Abiturs,
in seinem Studium zum Elektrotechnik-Ingeni-
eur, mit Schwerpunkt auf Informationstech-
nik, an der Hochschule in Karlsruhe, wider.

Anschließend vertiefte er sein Wissen im Mas-


terstudium im Bereich der regenerativen
Energiegewinnung an der Hochschule Karls-
ruhe für Technik und Wirtschaft.

138 Gratis eBook


Impressum:

Autor: Benjamin Spahic


Konradin-Kreutzer-Str. 12
76684 Östringen
Lektor/ Korrektorat: Mentorium GmbH
Cover: Kim Nusko
ISBN Taschenbuch: 9798585888335
ISBN Hardcover: 9798710129128
ASIN eBook: B08R7ZB4ZK
Linkedin: Benjamin Spahic
Instagram: Benjamin.Spahic.Autor
EMail: BenjaminSpahic@pbd-verlag.de
Python ohne Vorkenntnisse
Ersterscheinung 15.12.2020
Vertrieb durch kindledirectpublishing
Amazon Media EU S.à r.l., 5 Rue Plaetis, L-2338, Luxembourg
Haftungsausschluss

Der Autor übernimmt keinerlei Gewähr für die Aktualität, Vollständigkeit und
Richtigkeit der bereitgestellten Informationen. Außerdem kann keine Garantie
für das Erreichen der beschriebenen Fähigkeiten übernommen werden.

Bildnachweise:
https://icons8.de/icon/113140/kugelbirne
https://icons8.de/icon/79638/obligatorische
https://icons8.de/icon/78038/math
https://icons8.de/icon/42314/taschenrechner

Alle nicht-genannten Inhalte wurden vom Autor selbst erstellt. Er ist daher Urheber der Grafiken und hat
die Verwendungs- sowie Verbreitungsrechte.
*: https://docs.python.org/3/library/functions.html
*: https://www.python.org/community/logos/
**: https://en.wikipedia.org/wiki/File:Datove_centrum_TCP.jpg
**: https://pixabay.com/de/vectors/schaltungen-gehirn-netzwerk-chip-5076888/

* Diese Datei wird unter der GNU-Lizenz für freie Dokumentation zur Verfügung gestellt.
https://commons.wikimedia.org/wiki/Commons:GNU_Free_Documentation_License,_version_1.2
Es können Änderungen vorgenommen sein.
** Diese Datei wird unter der Creative-Commons-Lizenz „CC0 1.0 Verzicht auf das Copy-
right“ zur Verfügung gestellt.
https://creativecommons.org/publicdomain/zero/1.0/deed.de
Es können Änderungen vorgenommen sein.

Gratis eBook 139

Das könnte Ihnen auch gefallen