wird von einer starken Community getragen und weiterentwickelt
ist modular aufgebaut und kann durch eine große Zahl verfügbarer, nützlicher Bibliotheken (=Erweiterungen, Englisch: Libraries) erweitert werden.
Ein bedeutender Grund für die Beliebtheit von Python ist die große Zahl frei verfügbarer Materialien wie zum Beispiel
Einführungen (Englisch: Tutorials), Gratis-Bücher, Beispielprogramme, Erweiterungen, etc. Vieles davon ist auf Englisch
einiges aber auch auf Deutsch.
Eine wichtige Anlaufstelle für Python ist die Seite der Python Software Foundation.
Rechengeschwindigkeit (Performance)
Python entstand zuerst als Lehrsprache im akademischen Bereich. Deshalb war Geschwindigkeit (Performance) nicht das wichtigste Ziel.
Python ist in der Ausführung wesentlich langsamer als C und deutlich langsamer als Java. Das ist aber weniger eine Eigenschaft der Sprache selbst als
der konkreten Implementierung.
Abhilfe
In zukünftigen Implementierungen von Python sind hier Verbesserungen zu erwarten.
Üblicherweise wird bei großen, rechenintensiven Systemen das Backend mit C oder C++ implementiert das Frontend wird mit Python angesteuert.
Es gibt alternative Implementierungen die speziell auf Rechengeschwindigkeit ausgerichtet sind (pypy, Cython, ...).
Die wichtigsten Eigenschaften von Python
In Python wird zwischen Groß- und Kleinschreibung unterschieden (Auf Englisch sagt man die Sprache ist "case sensitive").
Das gilt sowohl für die reservierten Wörter als auch für Variablennamen.
Für diejenigen, die schon eine andere Programmiersprache kennen, ist die folgende Liste interessant:
Es gibt am Zeilenende kein ";".
Die Einrückungen (Englisch: "indents") sind Teil der Sprache und obligatorisch.
Das wirkt zuerst exotisch ist aber wenn man sich daran gewöhnt hat sehr praktisch.
Bilden von Blöcken wird über Einrückungen erzielt und nicht mit "{}" (C-Sprachen) oder "Begin End" (Pascal).
Variablen müssen vor ihrer ersten Verwendung nicht deklariert werden
Achtung: Python ist trotzdem eine "stark typisierte" Sprache. Es gibt verschiedenen Umwandlungsfunktionen für Datentypen.
Zuweisungen haben die Form: x = 7
Ab dieser Zuweisung hat die Variable den Wert 7
Ein Vergleich (um ihn von der Zuweisung unterscheiden zu können) hat die Form: x == 9
Das Ergebnis dieses Vergleichs ist ein Boolscher Wert
Die Zuweisung der Form i = i + 1 bedeutet, dass i nach der Durchführung um 1 erhöht ist.
Weil das oft vorkommt, gibt es dafür die Kurzschreibweise: i += 1
Statt 1 können natürlich auch andere Werte genommen werden: i += 129
auch i *= 2 und i /= 2 sind erlaubt mit entsprechender Bedeutung
Python wird interpretiert
Vereinfacht dargestellt gibt es 2 Arten von Programmiersprachen: Compiler und Interpreter.
Python gehört zur 2. Gruppe. Das hat den Vorteil, dass ein Programm nicht nach jeder Änderung in Maschinensprache
übersetzt (=kompiliert) werden muss. Andererseits bedeutet es aber, dass Python auf jedem Computer installiert sein
muss, auf dem ein Pythonprogramm lauffähig sein soll. Für die meisten dieser Einschränkungen gibt es aber Abhilfen (zum Beispiel http://www.py2exe.org/).
Wie wird Python installiert?
Python wird (für Einsteiger recht verwirrend) in 2 Versionen angeboten: Version 2 und Version 3
Wann wählt man welche Version?
Von Version 2 auf Version 3 wurden einige Verbesserungen vorgenommen die nicht abwärtskompatibel zur Version 2 sind,
das heisst Python 3 Programme, die diese neuen Merkmale verwenden, laufen unter Python 2 nicht.
Deshalb gilt:
Schreibt man ein Programm ganz neu ohne fremde Bibliotheken (=Libraries) zu verwenden, dann greift man zu Python 3.
Ist man auf die Verwendung von solchen Bibliotheken angewiesen und diese existieren nur in der Python 2 Version,
dann greift man zu Python 2. Im Zweifelsfall installiertst du zuerst Python 3.
Die Installation ist denkbar einfach.
Windows
Eine Google Suche mit den Wörtern "Python herunterladen" oder "Download Python" liefert meist die richtige Adresse als erstes Suchergebnis: https://www.python.org/downloads/
Nach dem Herunterladen befindet sich die Datei python-x.y.z.exe im Downloads-Ordner, wobei x, y, z Ziffern sind, die die
Versionsnummer angeben. Die Ziffer z ändert sich in jeder neuen Version, die Ziffer y nur bei größeren Änderungen
und die Ziffer x zeigt an das es einige umfangreiche Änderungen in der neuen Version gibt, aber keine Angst,
üblicherweise können für ältere Versionen geschriebene Programme so wie sie sind weiterverwendet werden.
Klicke die heruntergeladene Datei mit einem Doppelklick an, ann öffnet sich folgendes Fenster:
Dort setzt man folgendes Häkchen:
Dadurch kann Python systemweit von überall aufgerufen werden.
Dann klickt man auf "Install Now". Nach kurzer Zeit sollte dann ein Fenster mit dem Text
"Setup was successful" erscheinen.
Wann würde man dieses Häkchen nicht setzen?
Wenn man auf einem Rechner mehrere verschiedene Python-Versionen parallel laufen lassen möchte. Zum Beispiel wenn man eine Anwendung hat die
eine bestimmte Version von Python benötigt.
Standardmässig wird Windows-Benutzern die 32-bit Version angeboten.
Diese Version kann man getrost auch auf 64-bit Windows-Versionen installieren.
Für Python gibt es auch eine 64-bit Version. Die ist für den Anfang aber nicht notwendig.
Linux
Auf vielen Linuxsystemen ist Python schon vorinstalliert.
Eventuell muss man aber bei der Konfiguration etwas nachhelfen.
Raspberry Pi
Nicht nur ist Python hier bereits installiert, das "Pi" in Raspberry Pi steht für Python und
zeigt das Bekenntnis des Mini-Computers zu dieser Programmiersprache.
MacOS
Python sollte bereits installiert und lauffähig sein, eventuell aber nicht in der letzten Version.
Die neueste Version findest du unter folgendem Link: https://www.python.org/downloads/mac-osx/
Python verwenden
Endlich ist es so weit. Python ist am Computer installiert. Wie kann ich es starten?
Fahre mit der Maus über das Windows-Start-Symbol in der linken unteren Ecke, klicke 1 mal und beginne auf
der Tastatur "pyth..." zu tippen. Während du tippst erscheint das Menü wie im Bild unten:
Dir werden 2 Möglichkeiten angeboten Python zu starten:
Durch Klicken der oberen Zeile ("Python (command line)") startest Du eine Python Eingabeaufforderung, diese wird auch "Shell" genannt. (In jüngeren Python-Versionen fehlt der Zusatz "command line")
Durch Klicken auf die zweite Zeile startest Du IDLE, wir werden später sehen was für Möglichkeiten sich dort bieten
Für die erste Möglichkeit brauchst du nicht unbedingt den hier gezeigten Link, die Python-Shell funktioniert in jeder
Windows-Eingabeaufforderung.
Die Windows-Eingabeaufforderung
Fahre wieder mit der Maus über das Windows-Start-Symbol in der linken unteren Ecke, klicke 1 mal und beginne auf
der Tastatur "cmd" zu tippen. Es erscheint dann folgendes Menü:
Klicke auf Eingabeaufforderung dann öffnet sich folgendes Fenster:
Schneller geht es mit: Fenster+r, tippe dann cmd und dann Enter.
Es öffnet sich die Windows-Eingabeaufforderung. Ein Cursor steht in der ersten Zeile und wartet auf Deine Eingabe.
Was ist die Windows-Eingabeaufforderung?
Die Windows-Eingabeaufforderung wird auch manchmal Kommandozeile oder Shell genannt, ist gleichsam ein zusätzlicher,
leistungsstarker Zugang zum Betriebssystem Deines Computers. Die Windows-Eingabeaufforderung ist sehr mächtig und
gerade deshalb absichtlich etwas versteckt. Hier sollen nur Benutzer arbeiten, die wissen was sie tun. In der Eingabeaufforderung
kann man Textbefehle eingeben und damit etwas bewirken oder auch nur Informationen erlangen. Gibst du hier zum Beispiel
"dir" (=directory) ein gefolgt von der Eingabetaste. Dann bekommst Du den Inhalt des aktuellen Verzeichnisses aufgelistet.
Probier das ruhig einmal aus. Mit "cd" kannst Du in eines der aufgelisteten Verzeichnisse wechseln und mit "cd .."
kannst du wieder um eine Ebene zurück.
Die Python Shell
Gib nun in der Eingabeaufforderung "python" ein:
Python meldet sich mit ">>>". Das heisst die Installation hat funktioniert und Python wurde auf dem System gefunden.
Die ">>>" nennt man auch den Prompt. Damit meldet sich Python und sagt: "Ich bin bereit für Deine Eingaben".
Führt die Eingabe von "python" hier zur Fehlermeldung:
Der Befehl "python" ist entweder falsch geschrieben oder konnte nicht gefunden werden.
Dann gibt es 2 Möglichkeiten:
Python wurde nicht richtig installiert
Python ist installiert wurde aber nicht gefunden
Versuch im ersteren Fall die Installation noch einmal und wenn es wieder nicht klappt, bitte jemand um Unterstützung.
Im zweiten Fall hat während der Installation das Setzen des Systempfads nicht geklappt. Vielleicht war
während der Installation das betreffende Häkchen nicht gesetzt? Entweder versuchst du eine Deinstallation und Neuinstallation
diesmal mit dem Häkchen, alternativ kann man diese Konfiguration auch manuell vornehmen:
Gib zuerst in der Windows Eingabeaufforderung "where python" ein und drücke die Eingabetaste:
C:\Users\administrator>where python
Windows meldet dann den Pfad von python.exe der könnte etwas so lauten (xy steht für die Versionsnummer):
Öffne dann:
Start > System > Erweiterte Systemeinstellungen > Umgebungsvariablen
Selektiere in der Rubrik "Systemvariablen" die Variable "Pfad" und drücke "Bearbeiten".
Füge dann den entsprechenden Python-Pfad ans Ende der Variablen hinzu, der alte und der neue Inhalt werden mit ";" getrennt. Das Ergebnis wäre dann zum Beispiel (xyz sind die Versionsnummern, sie müssen mit deiner Version übereinstimmen):
Alternativ zur lokalen Installation gibt es auch online-Varianten, zum Beispiel die hier gezeigte: https://repl.it/languages/python3
Eine lokale Installation ist aber für unseren Zweck zu bevorzugen.
Wenn alles geklappt hat, haben wir jetzt eine Python Shell zur Verfügung eine sehr gute Möglichkeit erste
Erfahrungen mit Python zu sammeln. Die Shell nennt man auch den "interaktiven Modus" denn auf jede Eingabe reagiert Python sofort mit
einem Ergebnis. Python "antwortet" sozusagen auf unsere Eingaben.
Hier zeigt sich die Stärke eines Interpreters. Die eingegebenen Programmstücke müssen
eben im Gegensatz zu einem Compiler nicht zuerst übersetzt werden.
Hello World (Vorgriff)
Traditionell das erste Programm, das man in jeder Programmiersprache lernt:
print("hello world!")
Ausdrücke (Expressions)
Was ist ein Ausdruck? Ausdrücke sind wichtige Bausteine von Programmen.
Ein Ausdruck besteht aus einer Kombination von Werten und Operatoren.
Ausdrücke werden ausgewertet und liefern dann wieder einen Wert.
Folgende Beispiele sind uns aus der Schule bekannt:
1
2+2
(3+5)*2
((3+5)*2+2)/3
...
Man kann Ausdrücke mit oder ohne Leerzeichen schreiben, je nach Geschmack.
(3+5)*2 ist äquivalent (3 + 5) * 2
Wohlgeformtheit von Ausdrücken
Der Aufbau von Ausdrücken ist bestimmten Regeln unterworfen. Kennst du Beispiele?
Erfüllt ein Ausdruck diese Regeln, dann nennt man ihn "wohlgeformt".
Andererseits kann er nicht ausgewertet werden und der Versuch liefert einen Fehler.
Einen Regelverstoß in diesem Zusammenhang heisst "syntaktischer Fehler". (Später werden wir sehen, dass es noch andere Arten von syntaktischen Fehlern gibt)
Die Python-Shell ist ein ideales Werkzeug um Ausdrücke zu testen. Während der Entwicklung eines Programms
lohnt es sich immer eine Shell offen zu haben wo schnell Ausdrücke getestet werden können.
Operatoren
Die folgende Tabelle zeigt einige wichtige Python-Operatoren.
Die Reihung erfolgt in absteigender "Operatorrangfolge" (Priorität):
Operatoren in der gleichen Zeile haben gleiche Priorität. Wenn man einen Ausdruck anhand dieser Tabelle auswertet beginnt man immer mit dem Operator der am weitesten oben in der Tabelle steht. Stehen zwei Operatoren in der gleichen Zeile, dann wertet man den Ausdruck von links nach rechts aus.
Wenn keine Klammern vorhanden sind, wird zum Beispiel * vor + ausgewertet, da * in der Liste vor + steht. Ebenso wird "and" vor "or" ausgewertet, da "and" in der Liste vor "or" steht.
Durch Klammern kann man eine andere Auswertungsreihenfolge bewirken aber Klammern können einen Ausdruck auch lesbarer machen.
Jetzt lässt sich unsere Liste von Ausdrücken noch weiter ausbauen:
Die Verwechslung von "=" und "==" ist einer der häufigsten Programmierfehler und passiert auch geübten Programmierern.
Ein großer Vorteil in Python ist, dass "a = 1" keine gültige Bedingung ist, so dass "if a = 1:" einen Fehler liefert.
"Überladen" von Operatoren (operator overloading)
Achtung!: "Überladen" von Operatoren kann für Anfänger sehr verwirrend sein. Um einen Ausdruck auszuwerten muss
man zuerst sicher sein, welchen Datentypen man vor sich hat.
Welche Ausgabe erzeugt folgende Anweisung. Erkläre das Ergebnis:
print("*"*3)
Welche Ausgabe erzeugt folgende Anweisung. Erkläre das Ergebnis:
print("a"<"b")
Datentypen
Man unterscheidet grundlegende und höhere Datentypen. Zunächst werden wir uns mit den Grundlegenen Datentypen beschäftigen.
Integer (Ganzzahl)
Enthält eine ganze Zahl jeder Größe, positiv oder negativ, wie 1 oder 3 oder 9999999 oder -712 oder 0.
Im Unterschied zu vielen anderen Sprachen sind Integers "unbounded", können also beliebig groß sein.
Das spart viel Aufwand, macht die Programme sicherer (Überlauf) und funktioniert weil Python selbst für jede Zahl so viel Speicher reserviert wie notwendig.
Gleitkommazahl (Float)
Enthält eine Dezimalzahl wie 11.456 oder -71.3 oder 29.0 (Achtung! "." statt ",")
Gleitkommazahlen sind auf den ersten Blick der umfassendere Datentyp. Haben aber entscheidende Nachteile.
Zum Beispiel ist ein Vergleich nicht so einfach wie bei ganzen Zahlen:
2.00000001
2.00000000
Sind die Zahlen gleich oder nicht?
Gleitkommazahlen werden auch verwendet, um sehr große oder sehr kleine Zahlen in wissenschaftlicher Notation darzustellen. So bedeutet zum Beispiel 5.0e30 eine 5 gefolgt von 30 Nullen. 1.7e-6 ist 0.000017, was bedeutet 1,7 dividiert durch 1 gefolgt von 6 Nullen.
Zeichenkette (String)
Enthält eine Zeichenkette (Engl.: string) also einen Text, zum Beispiel den Namen einer Person, wie Max Mustermann. Die hier demnächst verwendete input-Funktion liefert eine Zeichenkette.
Boolean (logischer Wert)
Enthält entweder wahr (True) oder falsch (False). Der Datentyp Boolean kann nur einen dieser zwei Zustände annehmen. Boolesche Werte entstehen auch durch Vergleiche.
Die Auswertung des Ausdrucks 3 < 4 ergibt zum Beispiel den booleschen Wert True (wahr).
Mittels der type-Funktion kann abgefragt werden, welcher Datentyp vorliegt.
Mit den Umwandlungsfunktionen kann zwischen den Datentypen konvertiert werden:
str
int
float
bool
...
Im folgenden Beispiel sieht man, wie die type-Funktion und Umwandlungsfunktionen verwendet werden können:
Variablen sind wie Behälter für einen Wert. Um Variablen voneinander zu unterscheiden haben sie Bezeichner.
Über diese Bezeichner wird auf die Werte zugegriffen.
x=2
y=x*2
print("x:", x)
print("y:", y)
gültige Variablennamen
Variablennamen unterliegen gewissen Regeln.
Das gilt auch für andere Bezeichner in Python (Funktionsnamen, Klassennamen, ...).
Erlaubte Zeichen sind:
a-z
A-Z
0-9
"_"
Verboten sind:
Leerzeichen
jegliche Sonderzeichen: ä,ö,ü,ß,?,%,...
Achtung!: Variablen mit Sonderzeichen funktionieren manchmal, manchmal auch nicht.
(Shell, IDLE, ...)
Ziffern an erster Stelle des Variablennamens
Reservierte Wörter (if, else, while, ...)
Gute Variablennamen drücken die Bedeutung/Verwendung des Werts aus, den sie enthalten. Zum Beispiel:
anzahl, summe, laenge, vorname, nachname, alter, temperatur_12_uhr, ...
strecke, winkel, entfernung, x, y, z (für Koordinaten)
Python-Konvention (PEP 8)
Variablennamen und Funktionsnamen werden klein, Klassen groß geschrieben.
insbesondere:
Variablen und Funktionen nicht wie eingebaute Funktionen oder Objekte!
str, int, round, ...
Problem ist, dass diese Funktionen dann stillschweigend überschrieben werden.
Man wird leider nicht davor gewarnt.
Kein Programm so nennen wie ein importiertes Modul!
Beides ist leider unter Umständen sehr schwer zu finden.
Zuweisung
x=2
vorname="max"
pi=3.14
ist_groesser_als = True
ist_nicht_groesser_als = not ist_groesser_als # Code ist wie Text
Achtung!: eine Zuweisung ist keine Gleichung.
x=x+1 ist eine gültige Zuweisung aber als Gleichung wäre es sinnlos.
Anweisungen
Manchmal entsprechen Anweisungen den Zeilen im Programm, eine Anweisung kann sich aber auch über mehrere Zeilen erstrecken.
name = input("Bitte geben sie ihren Namen ein: ")
print("Hallo", name)
Anweisungsfolgen
Einfache Programme bestehen manchmal lediglich aus Anweisungsfolgen.
x=2
x=x*2
print("x:",x)
Anweisungsfolgen werden streng in der Reihenfolge abgearbeitet.
Kommentare
Man unterscheidet einzeilige "#" und mehrzeilige Kommentare: """
Zweck: Für denjenigen bestimmt, der den Code liest, also unter Umständen auch für den Autor selbst.
Solche Kommentare nicht notwendig. Selbsterklärend.
x=3 # Der Variablen x wird der Wert 3 zugewiesen
"""
Mit dem dreifachen Hochkomma
kann man einfach
mehrere Zeilen
auskommentieren
"""
Die obige Methode kann auch dazu dienen ganze Programmteile auszukommentieren und damit inaktiv zu schalten.
Zunächst vielleicht etwas verwirrend:
Auch mehrzeiligen Text im Programm schreibt man mit dreifachem Hochkomma.
Python ist eine textorientierte Sprache. Python-Programme kann man mit jedem Texteditor schreiben.
Eine integrierte Entwicklungs Umgebung oder IDE unterstützt beim Programmieren.
Bei der Python-Standardinstallation ist eine einfache aber gute IDE namens "IDLE" schon vorinstalliert.
Wichtigste Merkmale von IDLE.
Farbige Syntaxhervorhebung
IDLE enthält eine eigene Shell
Menü für Dateiverwaltung: Neue Datei, Öffnen, Speichern, Speichern unter, Zuletzt verwendet, ...
Starten eines Programms über Menü oder F5
Unterstützung bei der Fehlersuche: "Debugger" (Breakpoints, Einzelschritte)
Öffnet und startet man ein Pythonprogramm dann sind 3 Fenster vorhanden
der Quellcode
das Anwendungsfenster: hier läuft das Programm ab
eine Python-Shell, wo alle print()-Ausgaben und eventuelle Fehlermeldungen angezeigt werden
Mit Alt+tab wechselt man zwischen den Fenstern. Schließen kann man sie unter Windows mit Alt+F4 oder mit dem "x" rechts oben..
(Für andere Betriebssysteme gibt es gleichbedeutende Shortcuts)
Achtung!
Python-Programme dürfen nicht die gleichen Namen erhalten wie verwendete Python-Module.
Zum Beispiel führt eine selbst erstellte Programmdatei "turtle.py" zu einem Fehlerhalten.
Leider erhält man in dem Fall keine Fehlermeldung.
Die if-Anweisung
Einfache Programme bestehen manchmal nur aus Anweisungsfolgen aber diese können weder auf äußere Bedingungen noch auf innere Zustände reagieren.
Der Programmablauf hat keine Varianten und ist streng linear.
if <bedingung>:
<anweisungsblock>
Bei folgendem Beispiel kommt die input-Funktion zum Einsatz, die bisher nicht erklärt wurde.
Die input-Funktion erwartet eine durch Enter abgeschlossene Benutzereingabe. Man kann der input-Funktion einen Text übergeben
der ausgegeben wird. Die Benutzereingabe wird als Text zurückgeliefert (auch wenn der Benutzer eine Zahl eingibt).
>>> str = input("Tippe etwas ein: ")
Tippe etwas ein: Test
>>> str
'Test'
>>>
temp = int(input("Wie kalt ist es heute?: "))
if temp < 0:
print("Vorsicht Glatteis!")
Man beachte hier, dass das Programm scheitert, wenn der Benutzer keine ganze Zahl eingibt.
Einrückungen in Python
Die Verwendung von Einrückungen zur Bildung von Blöcken ist eine Besonderheit von Python.
Dieses Merkmal wirkt auf Umsteiger von anderen Sprachen zunächst gewöhnungsbedürftig ist aber sehr praktisch.
else
Häufig braucht man auch Entscheidungen der folgenden Form:
temp = int(input("Wie kalt ist es heute?: "))
if temp < 0:
print("Vorsicht Glatteis!")
else:
print("Vermutlich heute kein Glatteis.")
elif (else if)
Mit dem elif Zweig ist das if-Konstrukt komplett:
temp = int(input("Wie kalt ist es heute?: "))
if temp < 0:
print("Vorsicht Glatteis!")
elif temp > 0:
print("Heute sicher kein Glatteis.")
else: # temp == 0 (alles rechts von "#" ist nur ein Kommentar)
print("Es hat genau Null Grad.")
Der elif-Zweig darf als einziger mehrfach vorkommen.
Aufgabe:
Schreibe ein Programm, das den Benutzer auffordert sein Alter einzugeben. Das Programm soll feststellen ob der
Benutzer unter 13, ein Teenager (13-19) oder ob er älter ist. Das Programm soll dann eine entsprechende Ausgabe machen.
Verwende dazu die input-Funktion.
Schleifen
In Python gibt es 2 Arten von Schleifen.
for-Schleifen
Vor allem praktisch wenn man vorab weiß, wie oft man die Schleife durchlaufen will
Oft - aber nicht immer - kommt hier die range-Funktion zum Einsatz.
Versuch einmal folgendes in der Shell einzugeben:
print(list(range(10)))
for i in range(10):
print(i)
Spezialfall:
for char in "abcdef":
print(char)
Analog bei Listen
while-Schleifen
Diese sind vor allem praktisch wenn man die Anzahl der Durchläufe nicht genau weiß aber eine Schleifenbedingung leicht angeben kann.
i = 0
while i < 10: # "i < 10": Schleifenbedingung
print(i)
i=i+1 # Diese Zeile sehr wichtig wegen Abbruchbedingung!
Der Programmierer ist selbst verantwortlich, dass die Abbruchbedingungen tatsächlich erreicht wird. Oft kommt es unbeabsichtigt
zu einer Endlosschleife.
Aber manchmal will man ganz bewusst eine Endlosschleife (zb für die Implementierung eines Dienstes):
while True:
print(".", end="")
print("Auf Wiedersehen") # Diese Zeile wird niemals erreicht: "toter Code"
break
Die break-Anweisung beendet die Schleife vorzeitig, das Programm wird aber weiter ausgeführt.
Nun sehen wir, dass eine "while True:"-Schleife nur dann eine Endlosschleife ist, wenn sie kein erreichbares "break" enthält.
In dem Zusammenhang ist eine "while True:"-Konstruktion eine durchaus sinnvolle Möglichkeit.
Aufgabe:
Schreibe ein Programm, das den Benutzer auffordert ganze Zahlen einzugeben.
Durch die Eingabe von "q" soll das Programm beendet werden.
Vorher soll aber die Summe der eingegebenen Zahlen ausgegeben werden.
Listen
Listen gehören zu den höheren Datentypen. Höhere Datentypen sind im Gegensatz zu grundlegenden Datentypen nicht atomar.
Mit ihnen können Serien von Werten (zum Beispiel eine Messwertreihe) oder Kompositionen (zum Beispiel ein Personendatensatz bestehend aus Vorname, Nachname, Geburtsdatum, ...) dargestellt werden.
Auf folgende Weise kann eine Liste in Python erstellt werden:
Die Namen der Haustiere sind hier die Elemente.
Auf Elemente kann dann über ihren sogenannten Index zugegriffen werden,
indem zuerst der Name der Liste oder des Tupels und dann die Position
des Elements in eckigen Klammern angegeben wird.
Achtung!:
Nicht nur in Python, sondern auch in fast allen anderen Programmiersprachen beginnt man
aber bei der Zählung nicht mit 1 sondern mit 0!
Die Eingabe von haustiere[3] liefert also nicht, wie man vielleicht vermuten würde 'Hamster', sondern:
'Goldfisch'!
Das ist ein fundamentaler Unterschied, eine mögliche Fehlerquelle und jeder Programmieranfänger
braucht mehr oder weniger Zeit, sich daran zu gewöhnen.
haustiere [0] liefert also demnach 'Katze' und Eingabe von haustiere alleine liefert die ganze Liste.
Hier auch noch ein kleiner Trick: haustiere[-1] liefert das letzte Element der Liste also "Hase".
Der folgende Befehl sortiert die Liste namens haustiere:
haustiere.sort()
Beispiel:
Namen = ["David", "Anna", "Peter", "Paul", "Luise"]
print("Die Namen sind:", Namen)
Namen.sort()
print("Die Namen in sortierter Reihenfolge sind:")
print(Namen)
Bei Ausführung ergibt das:
>>>
Die Namen sind: ['David', 'Anna', 'Peter', 'Paul', 'Luise']
Die Namen in sortierter Reihenfolge sind:
['Anna', 'David', 'Luise', 'Paul', 'Peter']
>>>
Schnitt-Operator (slice operator) für Listen
Dieser liefert Teile von Listen zurück:
Liste[n:m] liefert eine Liste zurück mit Elementen der Liste beginnend beim Element mit dem Index n inklusive bis zum Element mit dem Index m exklusive.
Der untere (n) und obere Index (m) können aber auch entfallen, also sind auch folgende Varianten erlaubt:
Liste[n:]: liefert eine Liste mit allen Elementen von "Liste" aber ohne Elemente mit Index < n
Liste[:m]: liefert eine Liste mit allen Elementen von "Liste" aber ohne die Elemente mit Index >= m.
Liste[:]: liefert eine Kopie der Liste mit allen Elementen von "Liste".
Zum Durchlaufen von Listen wird die for-Schleife wie folgt verwendet:
haustiere = ["Katze","Hund","Hamster","Goldfisch","Hase"]
for element in haustiere:
print(element)
Gemischte Listen
In Python sind gemischte Listen erlaubt, das heisst die Elemente müssen nicht alle den gleichen Datentyp haben.
(Das ist gar nicht so selbstverständlich)
Also ist folgendes erlaubt:
Mix_List = ["abc", 1, 3.5, False]
Listen von Listen
werden später behandelt
Eingebaute Methoden für Listen
Mit dem dir-Befehl (funktioniert mit jedem Objekt) werden diese angezeigt. Methoden mit "__" können vorerst ignoriert werden (zum Beispiel __add__ entspricht dem "+"-Operator):
Hier findet man alle grundlegenden nützlichen Funktionen zu Listen wie zum Beispiel Hinzufügen, Entfernen, ...
Achtung!: was liefert list.count()?
Versuche auch:
help(list)
oder:
help(list.insert)
In diesem Sinne können wir herausfinden, dass list.count nicht die Anzahl der Elemente einer Liste liefert, denn dazu bräuchte die Methode keinen zusätzlichen Parameter.
Die count-Methode liefert die Anzahl der Elemente eines bestimmten (übergebenen) Werts. Für die Gesamtzahl der Elemente genügt "len()" (eingebaute Funktionen).
Anmerkung: wann verwendet man objektorientierte Schreibweise "Objekt.Methode()" wann verwendet man klassische Schreibweise "Funktion(Parameter)"?
Verwenden wir diese Information zur Demonstration einer möglichen Arbeitsweise mit Listen:
dir() und help() funktionieren auch mit eingebauten Objekten:
int (integer), float, bool, str (strings), dict (dictionaries), list, tuple, set, ...
Und auch mit importierten Objekten:
>>> import math
>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
>>> help(math.sin)
Help on built-in function sin in module math:
sin(...)
sin(x)
Return the sine of x (measured in radians).
>>>
Tupel
Für sie gilt alles was für Listen gesagt wurde, mit der Ausnahmen, dass einmal erstellte Tupel nicht mehr
verändert werden können.
haustiere = ("Katze","Hund","Hamster","Goldfisch","Hase")
for element in haustiere:
print(element)
print(haustiere[3])
haustiere.insert(2, "Goldfisch")
Liefert:
>>>
Katze
Hund
Hamster
Goldfisch
Hase
Traceback (most recent call last):
File "C:/Python34/haustiere.py", line 4, in <module>
haustiere.insert(2, "Goldfisch")
AttributeError: 'tuple' object has no attribute 'insert'
>>>
Funktionen
Eine Funktion ist ein Stück Programmcode, das von verschiedenen Stellen des Programms aufgerufen werden kann.
Funktionen kennst du bereits, denn Python verfügt über viele nützliche eingebaute Funktionen ohne die fast kein Programm auskommt.
input() und print() sind Beispiele für solche Funktionen:
input(): Wenn sie in einem Programm aufgerufen wird, fordert sie den Benutzer zu einer Eingabe auf und nimmt diese entgegen.
print(): Ist eine eingebaute Funktion, die eine Ausgabe am Bildschirm anzeigt.
Liste "eingebauter Funktionen" (built-in functions)
Ein gelegentliche Durchsicht dieser Liste ist jedenfalls empfehlenswert, weil sich hier nützliche Bausteine finden, auf die eigene Werke aufbauen können.
Manche eingbaute Funktionen verwendet man häufig, manche nur sehr selten:
Neben der Möglichkeit der Verwendung von eingebauten Funktionen ist aber gerade die Möglichkeit, selbst Funktionen erstellen zu können,
eine der wichtigsten grundlegenden Methoden einer Programmiersprache.
In Python wird das Schlüsselwort def (kurz für englisch "define") zur Definition einer Funktion verwendet.
Eine Funktion kann von jedem Ort im des Programms aufgerufen werden, indem sein Name angegeben wird.
Der Programmcode in der Funktion wird dann abgearbeitet und nach Fertigstellung wird das aufrufende Programm weiter ausgeführt und zwar ab der Stelle des Aufrufs.
Der Programmfluss springt sozusagen an die Stelle des Aufrufs zurück.
Es gibt Funktionen, die etwas tun ("do_...") und Funktionen die etwas liefern ("get_...") und Kombinationen daraus.
ohne Parameter
Es werden trotzdem die "()" verwendet, um von einer Variablen unterscheiden zu können.
Betrachten wir folgende Funktion:
def Sterne():
print("*****")
print("Vor dem Aufruf der Funktion Sterne()")
Sterne()
print("Nach dem Aufruf der Funktion Sterne()")
>>>
============= RESTART: C:/.../sterne.py =============
Vor dem Aufruf der Funktion Sterne()
*****
Nach dem Aufruf der Funktion Sterne()
>>>
Das ist die einfachste Art einer Funktion aber sie ist nicht sehr flexibel.
Es werden immer 5 Sterne ausgegeben.
mit einem/mehreren Parameter(n)
Die folgende Funktion ist eine verbesserte Variante der Funktion oben. Ein Parameter wird übergeben, der
steuert wieviele Sterne ausgegeben werden.
Die bisher erstellten Funktionen lieferten keinen Wert zurück: Funktion ohne Rückgabewert. Die gut bekannte print()-Funktion ist ein Beispiel für diese Gruppe.
Funktionen ohne Rückgabewert nennt man in anderen Programmiersprachen auch Prozedur.
Eine Funktion kann auch eine Berechnung ausführen und dem aufrufenden Programm einen Wert zurückliefern: Funktion mit Rückgabewert.
Die uns bereits gut bekannte input()-Funktion ist ein Beispiel für diese Gruppe.
#T(°C) = (T(°F) - 32) / 1.8
def Fahrenheit_nach_Celsius(Temperatur_in_Fahrenheit):
return int((Temperatur_in_Fahrenheit - 32) / 1.8)
print("-100 Fahrenheit sind in Celsius: ", Fahrenheit_nach_Celsius(-100))
print("0 Fahrenheit sind in Celsius: ", Fahrenheit_nach_Celsius(0))
print("100 Fahrenheit sind in Celsius: ", Fahrenheit_nach_Celsius(100))
Zentraler Punkt dabei ist die für uns neue return-Anweisung, gebildet aus dem
"return"-Schlüsselwort und gefolgt vom Rückgabewert. Die return-Anweisung beendet
die Ausführung der Funktion und liefert den Rückgabewert zurück. Eventueller Programmcode
nach einer return-Anweisung wird nicht mehr ausgeführt ("toter" Code). Über einen Aufruf:
if <Bedingung>:
return
kann das aber nicht pauschal gesagt werden. Der return Befehl muss also nicht die letzte Anweisung in der Funktion sein.
Im aufrufenden Programm wird dann der Funktionsaufruf durch den Rückgabewert ersetzt. Aus:
print("-100 Fahrenheit sind in Celsius: ", Fahrenheit_nach_Celsius(-100))
wird nach der Ausführung der Funktion und Einsetzen des Rückgabewerts:
print("-100 Fahrenheit sind in Celsius: ", -73)
Eine Ausführung des Programms liefert demnach:
>>>
RESTART: .../Fahrenheit_nach_Celsius.py
-100 Fahrenheit sind in Celsius: -73
0 Fahrenheit sind in Celsius: -17
100 Fahrenheit sind in Celsius: 37
>>>
Im dem kleinen Programm oben haben wir den Rückgabewert in int umgewandelt weil sich durch die Division
lange Kommazahlen ergeben würden. Stattdessen hätten wir auch eine Rundung vornehmen können um die Werte genauer ausgeben zu können.
Python stellt dafür die eingebaute Funktion "round()" zur Verfügung, mit der man zum Beispiel
auf 2 Nachkommastellen runden kann. Ändere die Zeile:
Auch die eingebaute Funktion "round()" ist eine Funktion mit Rückgabewert.
Man übergibt ihr 2 Übergabeparameter: die zu rundende Zahl und die Anzahl der Stellen auf die gerundet werden soll. Gehe auch bei den folgenden 2 Zeilen so vor und starte das Programm.
Achtung! Ein häufiger und sehr nachvollziehbarer Anfängerfehler bezüglich Funktionen mit
Rückgabewert kann mit folgendem Beispiel-Programm gezeigt werden:
def double(Zahl):
return Zahl * 2
double(10)
Betrachte das Programm und versuche vorherzusagen, was beim Aufruf passieren wird.
Ist das Programm fehlerfei? Wird es funktionieren wie gewünscht? Probiere das Programm aus.
Schlage Lösungen vor.
Auflösung:
Das Programm ist syntaktisch korrekt (es enthält keine syntaktischen Fehler).
Allerdings enthält das Programm einen semantischen Fehler, welcher schwieriger zu finden ist,
als ein syntaktischer Fehler. Die Funktion ist richtig definiert und sinnvoll benannt.
Der Aufruf ist in Ordnung, aber das Problem ist, dass mit dem von der Funktion zurückgelieferten
Rückgabewert nichts geschieht. Der Wert wird weder ausgegeben, noch sonstwie weiterverwendet.
Nach dem Start terminiert das Programm nach kurzer Rechenzeit, aber es passiert nichts.
Eine mögliche Behebung wäre die Zeile:
double(10)
zu ändern in:
print("Das Ergebnis ist:", double(10))
Boolesche Funktionen
Das sind Funktionen die als Ergebnis nur True oder False liefern können.
Diese können als Bedingung (zum Beispiel in if, while) verwendet werden.
Es muss nicht
if f()==True:
...
geschrieben werden.
if f():
...
genügt vollkommen.
Dasselbe gilt auch für boolsche Variablen.
Funktionen sind auch eine wichtige Möglichkeit ein Programm zu strukturieren.
Dictionaries +! erweiterter Inhalt
Ein weiterer wichtiger Datentyp in Python. Ähnlich einer Liste aber die Elemente werden
nicht über einen Index angesprochen sondern über einen "Schlüssel". Man sagt auch,
dass Dictionaries Listen von Schlüssel/Wert-Paaren sind.
Die Reihenfolge im Dictionary ist nicht garantiert.
dict = {"eins":"one", "zwei":"two", "drei":"three", "vier":"four"}
for key in dict:
print ("key:", key, "dict[key]:", dict[key])
Das obige Programm liefert:
>>>
key: eins dict[key]: one
key: drei dict[key]: three
key: vier dict[key]: four
key: zwei dict[key]: two
>>>
Verschachtelte Dictionaries (nested dictionaries)
...
Importieren von Modulen
Mittels Import von Modulen kann man die Funktionalität von Python erweitern.
Es gibt mehrere Arten diesen Import durchzuführen.
import random
Obst = ["Apfel", "Birne", "Banane", "Orange"]
print(random.choice(Obst))
for i in range(10):
print(random.randint(1,6))
for i in range(10):
print(random.randrange(1,7))
In Python gibt es eine großartige Möglichkeit, auf einfache Art mit Grafikprogrammierung zu
beginnen. Traditionell wird dieses Modul Turtle-Grafik genannt, weil es um eine gedachte
Schildkröte geht, die, während man sie mit Befehlen steuert, einen farbigen Strich zieht, wo
immer man sie hinschickt. Die Farbe und Stärke des Stifts steuert man auch über Befehle und
man kann den Stift heben und senken.
Nachdem man mittels "from turtle import *" die Turtle-Bibliothek importiert hat, kann man auf
alle Turtle-Befehle zugreifen. Ein Teil dieser Befehle ist hier aufgelistet, bei vielen Befehlen gibt
es eine Lang- und eine Kurzform (zum Beispiel forward und fd) - es spielt keine Rolle, welche
der beiden man verwendet.
Turtle-Befehle:
fd(Strecke) (forward)
Die Schildkröte bewegt sich um "Strecke" nach vorne.
bk(Strecke) (back)
Die Schildkröte bewegt sich um "Strecke" rückwärts.
lt(Winkel) (left)
Die Schildkröte dreht sich um "Winkel" nach links.
rt(Winkel) (right)
Die Schildkröte dreht sich um "Winkel" nach rechts.
pu() (pen up)
Die Schildkröte hebt den Zeichenstift an (und schreibt nicht mehr).
pd() (pen down)
Die Schildkröte senkt den Zeichenstift (und schreibt wieder).
pensize(Breite)
setzt die Stiftdicke auf "Breite".
pencolor(Farbe)
setzt die Stiftfarbe auf "Farbe".
shape(Form)
setzt die Form der Schildkröte (‘arrow’,‘classic’,‘turtle’,‘circle’).
home()
Schildkröte kehrt nach (0,0) zurück (Mitte des Zeichenblatts).
clear()
Löschen der Zeichnung, Schildkröte ändert Zustand nicht.
reset()
Löschen der Zeichnung, Schildkröte geht in Ausgangszustand.
setup(Breite, Hoehe)
Fenster mit "Breite", "Hoehe" erzeugen.
heading()
In welche Richtung schaut die Schildkröte? (3-Uhr-Position = 0)
setheading(Winkel)
Drehe die Schildkröte in Richtung "Winkel" (3-Uhr-Position=0).
goto(x, y)
Bewege die Turtle zur Position x, y.
(Falls pen=down wird auch gezeichnet. Ändert die Orientierung nicht.)
dot(size, color)
Zeichnet einen Kreis der Größe "size" und der Farbe "color" an der aktuellen Position.
towards(x, y)
Liefert den Winkel, den sich die Schildkröte drehen müsste um auf x, y zu zeigen.
Mit Turtle-Grafik kann man auf einfache Art tolle Grafiken erstellen und auf anschauliche Art
viel über Programmierung lernen, weil man sozusagen den Programmen bei der Arbeit zusehen
kann.
Und hier zur Demonstration ein Beispielprogramm:
from turtle import *
setup(400,400) # Legt ein Fenster dieser Größe an
shape('turtle') # Zeigt die Schildkröte
fd(50) # 50 Einheiten nach vorn
lt(90) # Dreht um 90 Grad nach links
pencolor('red') # Stiftfarbe ist ab jetzt "rot"
fd(70)
lt(90)
fd(110)
pencolor('blue') # Stiftfarbe ist ab jetzt "blau"
rt(90) # Dreht um 90 Grad nach rechts
bk(100) # Fährt 100 Einheiten zurück
pu() # pen up: Hebt den Stift ab
lt(45)
bk(50)
pd() # pen down: Senkt den Stift ab
pensize(5) # Ändert Stiftgröße auf 5
bk(70)
pensize(1)
home() # Geht zum Ursprung
Hier das Ergebnis beim Aufruf des Programms:
Und hier noch ein fortgeschrittenes Beispiel:
import turtle, colorsys
turtle.setup(350,350)
turtle.pensize(10)
turtle.color("#ff0000")
turtle.fd(10)
turtle.color("#00ff00")
turtle.fd(10)
turtle.color("#0000ff")
turtle.fd(10)
hue=0.0
i = 0
while True:
turtle.fd(1)
turtle.lt(1)
turtle.color(colorsys.hsv_to_rgb(hue, 1, 1))
hue+=0.01
i = i + 1
if i > 315:
break
Ausgabe des Programms:
Ereignisorientierte Programmierung
In der Programmierung gibt es verschiedene fundamentale Ansätze. Mehrere davon kennst du
schon, denn sie sind fester Bestandteil der traditionellen Programmierung:
Die funktionale Programmierung: Verwendung von Funktionen mit Rückgabewerten
ohne "Seiteneffekte".
Die prozedurale Programmierung: Verwendung von Funktionen ohne
Rückgabewert.
Die objektorientierte Programmierung: Verwendung von Klassen und Methoden.
Teile davon waren schon Bestandteil dieses Handbuchs und der enthaltenen Beispiele.
In diesem Kapitel wird ein weiterer Ansatz vorgestellt. Auch dieser ist Bestandteil der
traditionellen Programmierung, er ist aber nicht ganz so universell anzutreffen wie die drei oben
erwähnten Ansätze. Im Zusammenhang mit der Programmierung von graphischen
Benutzerschnittstellen (Graphical User Interfaces = GUIs) kommt dieser Ansatz verstärkt um Einsatz.
Bei der ereignisorientierten Programmierung (englisch Event-driven programming oder auch
Event-based programming) spielen Ereignisse eine zentrale Rolle in der Programmlogik. Jede
Aktion des Benutzers, zum Beispiel Mausbewegungen, Klicks, Drücken von Tasten, löst
Ereignisse aus. Aber auch Mechanismen innerhalb des Programms können Ereignisse auslösen,
wie etwa der Ablauf einer festgelegten Zeitspanne, das Eintreffen von Daten oder das Beenden
einer vorher gestarteten Aufgabe. Auch vom Rechner selbst können Ereignisse ausgelöst werden,
zum Beispiel ein Notebook, dessen Akkustand unter eine gewisse Schwelle sinkt, könnte ein
speziell dafür vorherbestimmtes Ereignis auslösen.
Ereignisbehandlungsroutinen (Event handler)
Tastendruck-Ereignisse
Ereignisse sind speziellen Ereignisbehandlungsroutinen (Funktionen) zugeordnet, die aufgerufen
werden, sobald die Ereignisse eintreten. Zum Beispiel können den Pfeiltasten auf der Tastatur
(nach oben, nach unten, links, rechts) solche Ereignisbehandlungsroutinen zugewiesen werden. Je
nachdem, welcher Event auftritt (nach oben, nach unten, links, rechts), führt das Programm die
passende Ereignisbehandlungsroutine aus, die dann die richtige Bewegung der Schildkröte
ausführt.
Um diese ereignisorienierte Programmierung praktisch vorzustellen, eignet sich die oben
vorgestellte Turtle-Bibliothek ideal.
import turtle
turtle.setup(400,500) # Fenstergröße
wn = turtle.Screen() # wn repräsentiert das Fenster
wn.title("Tastendruck-Ereignisse") # Fenster Titel
wn.bgcolor("lightgray") # Hintergrundfarbe
schildkroete = turtle.Turtle() # Schildkröte anlegen
# Event-Handler:
def h1():
schildkroete.forward(30)
def h2():
schildkroete.left(15)
def h3():
schildkroete.right(15)
def h4():
wn.bye() # Fenster schließen
# Verknüpfung herstellen zwischen Tastenereignissen und Handlern
wn.onkey(h1, "Up")
wn.onkey(h2, "Left")
wn.onkey(h3, "Right")
wn.onkey(h4, "q")
# Mit "listen" fängt die Anwendung an nach Ereignissen zu "horchen".
# Ein richtiger Tastendruck löst den zugehörigen Eventhandler aus.
wn.listen()
wn.mainloop()
Mausklick-Ereignisse
Ich kann aber auch auf Mausklick-Ereignisse reagieren.
Ich füge nun folgenden Handler in das obige Programm ein:
Mittels der ontimer-Funktion wird festgelegt, dass die Funktion h1 nach 2 Sekunden aufgerufen wird.
Ergebnis:
Für manche Anwendungszwecke reicht das aus aber wenn eine Timer-Funktion regelmässig aufgerufen werden soll dann
muss man so vorgehen wir unten gezeigt:
Bauen wir nun diese Timer-Funktionalität in unser Beispiel ein:
import turtle
turtle.setup(400,500) # Fenstergröße
wn = turtle.Screen() # wn repräsentiert das Fenster
wn.title("Tastendruck-Ereignisse") # Fenster Titel
wn.bgcolor("lightgray") # Hintergrundfarbe
schildkroete = turtle.Turtle() # Schildkröte anlegen
# Event-Handler:
def h1():
schildkroete.forward(30)
def h2():
schildkroete.left(15)
def h3():
schildkroete.right(15)
def h4():
wn.bye() # Fenster schließen
def h5(x, y):
schildkroete.penup()
schildkroete.goto(x, y)
schildkroete.pendown()
#------------------- neu ------------------------
def h6():
if schildkroete.pensize() == 1:
schildkroete.pensize(10)
else:
schildkroete.pensize(1)
wn.ontimer(h6, 700)
#------------------------------------------------
# Verknüpfung herstellen zwischen Tastenereignissen und Handlern
wn.onkey(h1, "Up")
wn.onkey(h2, "Left")
wn.onkey(h3, "Right")
wn.onkey(h4, "q")
wn.onclick(h5) # "onclick" reagiert auf Mausklick
# Mit "listen" fängt die Anwendung an nach Ereignissen zu "horchen".
# Ein richtiger Tastendruck löst den zugehörigen Eventhandler aus.
wn.listen()
#------------------- neu ------------------------
h6()
#------------------------------------------------
wn.mainloop()
Und hier wieder ein Beispiel für eine Durchführung:
Rekursion
Aus der Schule erinnern wir uns an die Definition der Faktoriellen:
n! = n * (n-1)! (für alle n > 1))
n! = 1 (für n:0,1)
Betrachten wir folgende Funktion.
from turtle import *
setup(800, 800)
def zeichne_rekursiv(wie_oft_noch):
if wie_oft_noch < 1: # Abbruch der Rekursion
return
fd(wie_oft_noch)
lt(15)
# Rekursionsaufruf mit verringerter Größe:
zeichne_rekursiv(wie_oft_noch - 1)
zeichne_rekursiv(50)
Das Programm erzeugt folgendes Bild:
Rekursion kann anfänglich recht verwirrend wirken, denn eine Definition, die sich selbst enthält erinnert auf den ersten Blick an einen fehlerhaften Zirkelbezug. Zum Beispiel wie im folgenden Dialog:
"Kennst du Max?"
"Ja, das ist der Nachbar von Tom"
"Wer ist Tom?"
"Das ist der Nachbar von Max"
Tatsächlich handelt es sich aber bei unserer Funktion um keinen Zirkelbezug, weil bei einem Funktionsaufruf immer auch der Übergabeparameter eine Rolle spielt.
Erweitern wir die Funktion noch etwas:
from turtle import *
setup(800, 800)
def dreieck(groesse):
# Zeichnet ein Dreieck in der angegebenen Größe
# Nach dem Zeichnen ist die Schildkröte wieder
# in der ursprünglichen Position und hat den
# ursprünglichen Winkel
fd(groesse)
lt(120)
fd(groesse)
lt(120)
fd(groesse)
lt(120) # Ergänzt auf 360 Grad
def zeichne_rekursiv(wie_oft_noch):
if wie_oft_noch < 1: # Abbruch der Rekursion
return
fd(wie_oft_noch)
lt(15)
dreieck(wie_oft_noch)
# Rekursionsaufruf mit verringerter Größe:
zeichne_rekursiv(wie_oft_noch - 1)
zeichne_rekursiv(50)
Das Programm erzeugt folgendes Bild:
Rekursive Funktionen sind mächtige Werkzeuge und werden in der Informatik häufig verwendet. Ideal eigenen sich rekursive Funktionen auch zur Abarbeitung von rekursiven Datenstrukturen.
Rekursive Funktionen sind nicht auf grafische Anwendungen beschränkt es gibt zum Beispiel rekursive Suchverfahren.
Inhalte ab hier gehen über das Computing Modul hinaus
Textverarbeitung (Stringverarbeitung)
Erinnern wir und an das Beispiel des Durchlaufens einer Zeichenkette:
for char in "abcdef":
print(char)
Aber auch in anderen Fällen können Zeichenketten behandelt werden wie Listen:
>>> str_list = "abcdef"
>>> str_list[3]
'd'
Ansonsten ist die Suche einer Zeichenkette innerhalb einer anderen eine der grundlegendsten Operationen.
Dazu kann "in" verwendet werden. dieser Operator arbeitet grundsätzlich "case-sensitive".
Zur Vermeidung, muss man die lower-Methode einsetzen.
Braucht man die Position des gefunden Strings, verwendet man die find-Methode.
str = "eins zwei drei"
print("zwei" in str) # True
print("zwEi" in str) # False
print("zwEi".lower() in str) # True
print(str.find("zwei")) # 5
print(str.find("zwEi")) # -1
print(str.lower().find("zwEi".lower())) # 5
print(str.lower()) # "eins zwei drei"
print("zwEi".lower()) # "zwei"
Dateioperationen +! erweiterter Inhalt
Lesen
Zeilenweise:
with open("filename") as fileobj:
for line in fileobj:
print(line)
Einzelne Zeichen:
with open("filename") as fileobj:
for line in fileobj:
for ch in line:
print(ch)
Was ist, wenn es keine Zeilen gibt?:
with open(filename) as fileobj:
while True:
c = fileobj.read(1)
if not c:
print("End of file")
break
print("Read a character:", c)
"""
with open("romeo_und_julia.txt") as fileobj:
for line in fileobj:
#print(line)
print(line, end="")
"""
fileobj = open("romeo_und_julia.txt")
for line in fileobj:
print(line.rstrip())
#print(line, end="") # alternativ
fileobj.close()
Das führt zu einer sehr langen Ausgabe:
...
Denn nie verdarben Liebende noch so
Wie diese: Julia und ihr Romeo.
(Alle ab.)
Ende dieses Projekt Gutenberg Etextes Romeo und Julia, von
William Shakespeare (Uebersetzt von August Wilhelm von Schlegel)
Jetzt wollen wir aber nur die gefundenen Zeilen anzeigen:
search = "gift"
fileobj = open("romeo_und_julia.txt")
for line in fileobj:
if (search in line.lower()):
print(line.rstrip())
fileobj.close()
Das klappt schon besser. Das läuft wesentlich schneller. Warum eigentlich?:
Voll Pflanzen giftger Art und diensam zum Genesen.
Die kleine Blume hier beherbergt giftge Saefte
Und sagt du "Ja", vergiftet dieser Laut
...
Die Bildschirmausgaben verbrauchen oft erheblich mehr Zeit ale alle anderen Berechungen und Aufgaben: Flaschenhals.
Jetzt wollen wir aber auch die Zeilennummmern:
search = "gift" # gift, tod, liebe, verona, nachtigall
line_num = 1
num = 0
fileobj = open("romeo_und_julia.txt")
for line in fileobj:
if (search in line.lower()):
print(line_num, line.rstrip())
num += 1
line_num += 1
print()
print(num)
# print("\n" + str(num)) # alternativ
fileobj.close()
Das ist wesentlich Aussagekräftiger:
1730 Voll Pflanzen giftger Art und diensam zum Genesen.
1745 Die kleine Blume hier beherbergt giftge Saefte
2905 Und sagt du "Ja", vergiftet dieser Laut
3116 So hattest du kein Gift gemischt, kein Messer
3483 Ach, faendet Ihr nur jemand, der ein Gift
3825 Wie? Waer es Gift, das mir mit schlauer Kunst
3836 Des giftger Mund nie reine Luefte einhaucht,
4239 Beduerfte jemand Gift hier, des Verkauf
4481 In meines Trauten Hand?--Gift, seh ich, war
4486 Haengt noch ein wenig Gift daran und laesst mich
4708 Ihm Gift verkauft, womit er gehen wolle
11
Schreiben
Wir wollen nun in einer Log-Datei über alle Aufrufe Buch führen:
search = "liebe" # gift, tod, liebe, verona, nachtigall
line_num = 1
num = 0
fileobj = open("romeo_und_julia.txt")
fileobj_append = open("log.txt", "a") # "a" für append. Fehlt die Datei dann wird sie erzeugt.
for line in fileobj:
if (search in line.lower()):
print(line_num, line.rstrip())
num += 1
line_num += 1
print()
print(num)
# print("\n" + str(num)) # alternativ
fileobj_append.write(search + " " + str(num) + "\n")
fileobj.close()
fileobj_append.close()
In log.txt steht dann:
gift 11
tod 61
liebe 95
verona 11
nachtigall 2
Zuletzt möchte ich noch die Fundstellen hervorheben lassen:
search = "gift" # gift, tod, liebe, verona, nachtigall
line_num = 1
num = 0
fileobj = open("romeo_und_julia.txt")
for line in fileobj:
pos = line.lower().find(search)
if (pos > -1):
print(line_num, line.rstrip())
print(" "*len(str(line_num)) + " " + " "*pos + "="*len(search))
num += 1
line_num += 1
print()
print(num)
# print("\n" + str(num)) # alternativ
fileobj.close()
"""
markiert wird nur ein auftreten pro zeile.
markieren aller auftreten wäre etwas komplizierter.
"""
Das erzeugt dann:
1730 Voll Pflanzen giftger Art und diensam zum Genesen.
====
1745 Die kleine Blume hier beherbergt giftge Saefte
====
2905 Und sagt du "Ja", vergiftet dieser Laut
====
...
Schreiben einer Liste als csv-Datei +! erweiterter Inhalt
Folgendes Programm schreibt den Inhalt der Liste in eine Datei:
fileobj = open("export_list.csv", "w") # "w" für write also Schreiben.
# Eine eventuell vorhandene Datei wird überschrieben
list_1 = [
[3,1,True,5.7,"Demo"],
[9,1,False,15.27,"Test"],
[1,1,True,2.2,"Xyz"],
[4,1,True,4.8,"Muster"],
[8,1,False,9.7,"Abc"]
]
for record in list_1:
separator = ""
for element in record:
fileobj.write(separator + str(element))
separator = ";"
fileobj.write("\n")
fileobj.close()
print("Die Datei wurde exportiert.")
Das "Abfangen" von Ausnahmen (Exceptions) mittel try-except.
Erinnern wir uns an das vorige Beispiel.
Reduzieren wir das auf den reinen Lesevorgang.
from datetime import *
fileobj_read = open("demo.txt")
for line in fileobj_read:
print(line.rstrip())
fileobj_read.close()
Dateioperationen (Lesen, Schreiben, Anfügen) können scheitern.
Beispiele?
Diese Ausnahmen kann man auf diese Weise abfangen:
try:
fileobj_read = open("demo.txt")
for line in fileobj_read:
print(line.rstrip())
fileobj_read.close()
except:
print("Die Datei wurde nicht gefunden.")
# Alternativ: Fortsetzung möglich?
Ergebnis:
Die Datei wurde nicht gefunden.
>>>
Es geht auch folgendes:
try:
fileobj_read = open("demo.txt")
for line in fileobj_read:
print(line.rstrip())
fileobj_read.close()
except Exception as e:
print(e)
Ergebnis:
[Errno 2] No such file or directory: 'demo.txt'
>>>
Speichern einer Liste als JSON +! erweiterter Inhalt
Speichern der Liste:
import json
friends = ["Tina",["Peter",3],"Paul"]
friends_json = json.dumps(friends)
with open('data.txt', 'w') as outfile:
json.dump(friends_json, outfile)
Laden der Liste:
import json
with open('data.txt') as json_file:
data_str = json.load(json_file)
print(type(data_str))
data = json.loads(data_str)
print(type(data))
print(data)
Datenbanken sind ein wichtiges Werkzeug um Daten in strukturierter Weise auf Dauer
zu speichern, sie zu bearbeiten und darauf effizient zuzugreifen.
In folgendem Beispiel kommt eine SQLite Datenbank zum Einsatz.
"SQLite ist eine Bibliothek, die eine in sich geschlossene, serverlose, konfigurationsfreie, transaktionale SQL-Datenbank-Engine implementiert.
Der Code für SQLite ist gemeinfrei und kann daher zu jedem gewerblichen oder privaten Zweck verwendet werden. SQLite ist die am häufigsten
eingesetzte Datenbank der Welt, darunter mehrere hochkarätige Projekte."
Mit eventuellen kleinen Anpassungen funktionieren diese Programme aber auch mit
anderen Datenbanken.
Die Daten einer SQLite Datenbank werden in einer ".db" Datei abgespeichert.
Das folgende Programm legt eine Tabelle an und entfernt vorher eventuell schon
existierende Versionen. Falls die Datei employee.db nicht existiert wird sie
automatisch angelegt.
Alternativ dazu hier ein Programm zur manuellen Eingabe von Datensätzen.
Das wäre aber umständlich wenn es um mehr als einzelne Sätze geht.
import sqlite3
connection = sqlite3.connect("employee.db")
# Felder: firstname lastname gender joining birth_date
cursor = connection.cursor()
while True:
firstname = input("Bitte den Vornamen und 'Return' drücken (q=ende): ")
if firstname == "q":
break
lastname = input("Bitte den Nachnamen und 'Return' drücken: ")
gender = input("Bitte das Geschlecht (m oder f) und 'Return' drücken: ")
joining = input("Bitte das Eintrittsdatum und 'Return' drücken (JJJJ-MM-TT): ")
birth_date = input("Bitte das Geburtsdatum und 'Return' drücken (JJJJ-MM-TT): ")
sql_command = "INSERT INTO tbl_employee (firstname, lastname, gender, joining, birth_date) VALUES ('"+firstname+"','"+lastname+"','"+gender+"','"+joining+"','"+birth_date+"');"
cursor.execute(sql_command)
print("Auf Wiedersehen")
connection.commit()
connection.close()
Die Ausgabe aller Datensätze kann durch folgendes Programm erzielt werden:
import sqlite3
connection = sqlite3.connect("employee.db")
cursor = connection.cursor()
print("----------------")
cursor.execute("SELECT * FROM tbl_employee")
result = cursor.fetchall()
for record in result:
print(record)
print("----------------")
connection.close()
Folgendes Programm löscht alle Datensätze aus der Tabelle:
import sqlite3
# Alle Datensätze löschen
connection = sqlite3.connect("employee.db")
cursor = connection.cursor()
cursor.execute("delete FROM tbl_employee")
connection.close()
print("Alle Datensätze wurden gelöscht.")
Folgendes Programm importiert Datensätze aus der csv-Datei import.csv
und schreibt sie in die Tabelle:
import csv
import sqlite3
with open("import.csv", "r") as file:
import_list = csv.reader(file, delimiter = ";") # Lesen der Daten von Datei
connection = sqlite3.connect("employee.db")
cursor = connection.cursor()
for element in import_list:
print(element)
sql = """INSERT INTO tbl_employee (firstname, lastname, gender, joining, birth_date)
VALUES ('""" + element[0] + "','" + element[1] + "','" + element[2] + "','" + element[3] + "','" + element[4] + "');"
print(sql)
cursor.execute(sql) # Einfügen von Satz in Datenbank
print("Die Sätze wurde eingefügt.")
connection.commit()
connection.close()
import sqlite3
fileobj = open("export.csv", "w")
connection = sqlite3.connect("employee.db")
cursor = connection.cursor()
cursor.execute("SELECT * FROM tbl_employee")
result = cursor.fetchall()
for record in result:
fileobj.write(str(record[0])+";"+record[1]+";"+record[2]+";\
"+record[3]+";"+record[4]+";"+record[5]+"\n")
fileobj.close()
connection.close()
print("Die Datei wurde exporti-+ert.")
Beachte, dass das "\"-Zeichen verwendet wurde um die Zeile umzubrechen.
Python liest dann automatisch in der nächsten Zeile weiter und der Umbruch hat
für die logische Struktur des Programms keine Bedeutung.
Das ist ein Beispiel für die so erzeugte Datei export.csv:
Die oben gezeigt sqlite-Datenbank ist eine tolle Möglichkeit für kleine Projekte
oder um schnell loszustarten aber wenn sqlite an seine Grenzen stößt, sollte man
auf eine echte Serverdatenbank umstellen. Unten wird gezeigt, wie man zu einer mySQL
oder zu einer MariaDB Datenbank verbindet.
Passe die Verbindungsdaten entsprechend an: user, password, host, database).
Im Fall unten erfolgt die Verbindung zum sogenannten localhost (127.0.0.1).
Das beudeutet die Datenbank läuft am selben Rechner wie Python. Das muss natürlich
nicht so sein.
Damit das funktioniert, muss der verwendete Benutzer (in unserem Fall connnect_user)
die Berechtigung haben, sich zu verbinden. Möchte man sich nicht vom selben Rechner
(localhost) sondern von einem entfernten Rechner (remote) verbinden muss eine eigene
zusätzliche Berechtigung bei diesem Benutzer vorhanden sein.
Achtung! Um wie unten gezeigt, das mysql-Modul zu importieren, musst du vorher
das Modul installieren.
Öffne dazu eine Windows-Kommandozeile aber im Administratormodus:
Gib dann im Fenster folgendes ein:
C:\Users\python_fan>pip install mysql
Fenster-Taste > cmd > rechte Maustaste auf dem Kommandozeilensymbol
> Als Administrator ausführen
> pip install mysql
Die Installation könnte scheitern, wenn du nicht im Administratormodus bist.
Folgendes Beispiel zeigt die Verbindung zu einer Microsoft Access Datenbank.
Die Datei mydb.accdb muss an dem angegebenen Pfad vorhanden sein.
import pyodbc
conn = pyodbc.connect(r'Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\python\db\mydb.accdb;')
cursor = conn.cursor()
cursor.execute('select * from tbl_employee')
for row in cursor.fetchall():
print (row)
conn.close()
Installiere vor der Ausführung wie oben gezeigt mittels "pip install pyodbc"
das pyodbc-Modul.
Verwende wieder eine Windows-Kommandozeile im Administrator-Modus.
In der Access-Datenbank kannst du vorher mittels folgendem SQL-Skript die
Tabelle anlegen und dann befüllen:
Im obigen Fall wurde die Verbindung über eine
ODBC (Open Database Connectivity)
Schnittstelle hergestellt. Dafür müssen, zusätzlich zu Installation und Import des pyodcb
Moduls, 2 Voraussetzungen erfüllt sein:
Der ODBC-Treiber muss für die jeweilige Datenbank am Gerät installiert sein.
Das ist für Microsoft Access auf einem Windows-Gerät aber schon der Fall.
Wenn die Datei nicht, wie bei Access der Fall, als Datei angesprochen werden
kann, dann muss eine ODBC Datenquelle in der Systemsteuerung eingerichtet werden.
Webservices mit Python +! erweiterter Inhalt
...
Klassen +! erweiterter Inhalt
Im Gegenteil zu Java muss man in Python nicht immer objektorientiert programmieren.
Aber natürlich unterstützt Python als moderne Sprache auch das objektorientierte Paradigma.
Begriffsklärung
Klassen sind Baupläne für Objekte. Mithilfe eines "Konstruktors" (eine spezielle Funktion, die auch
Parameter haben kann) wird zur Laufzeit eine sogenannte Objektinstanz erstellt. Die Konstruktor-Funktion
ist namensgleich mit der Klasse (siehe zum Beispiel die Funktion Person() im Beispiel unten). Von einer Klasse kann es zu einem Zeitpunkt viele Instanzen geben.
Klassen sind maßgeblich zur Design-Zeit, Objekte zur Laufzeit.
Was ist ein Objekt?
Ein Objekt besteht aus Attributen und Methoden. Die Attribute beinhalten die Daten des Objekts.
Die Methoden können lesend oder schreibend auf diese Daten zugreifen und diese direkt oder daraus
abgeleitete Ergebnbisse zurückgeben.
Eine wichtige Eigenschaft von Objekten ist, dass ein Objekt einen Teil seines inneren Aufbaus und
Zustands nach außen verbergen kann. Es kann sogenannte private Attribute oder Methoden geben, welche
von außen (von außerhalb des Objekts) nicht oder nicht direkt zugänglich sind.
Praktisch ist bei Klassen, dass man meist die genaue Implementierung einer Methode nicht kennen muss.
Es genügt, wenn man versteht, was die Methode macht.
Motivation
In Python stehen hinter allen Datentypen Klassen. Deshalb kann man auch bei der Liste "haustiere" mit
dem Aufruf "haustiere.sort()" auf der Objektinstanz die dazugehörige Methode aufrufen. Diese
Schreibweise ist uns also durch ihre Verwendung durchaus schon bekannt. Eine einfache Erklärung für
objektorierte Programmierung ist also zu sagen, dass man mit Klassen selbstdefinierte Datentypen
erstellen kann.
Erklärung:
Die Definition einer Klasse wird mit dem "class"-Schlüsselwort eingeleitet.
Die "__init__"-Methode dient der Initialisierung.
name, birth_year, birth_month, birth_day sind in dieser Klasse die Attribute. Sie enthalten die
Daten des Objekts. get_age ist eine Methode des Objekts.
Achtung!:
Der Parameter "self" hat eine spezielle Bedeutung. Mit ihm kann man auf die aktuelle Objektinstanz zugreifen.
Diesen Parameter muss jede Klassenemethode (also auch init) haben und per Konvention wird meist der Name "self" verwendet,
das ist aber nicht verpflichtend.
In der init-Methode bezieht sich "self" also auf das neu erstellte Objekt. In anderen Klassenmethoden
bezieht es sich auf die Instanz, deren Methode aufgerufen wurde.
In unserem Fall hat init aber noch weitere Parameter, nämlich Namen und Geburtsdaten. Mithilfe der
"self"-Variablen werden die übergebenen Werte dem Objekt zugewiesen.
Die get_age-Methode verwendet diese Werte um das Alter der Person zu ermitteln.
Im Hauptprogramm wird schließlich mithilfe des Konstruktors "Person()" eine Objektinstanz (oder
kurz ein Objekt) der Klasse erstellt. Bei Erstellung des Objekts wird automatisch die init-Methode
aufgerufe und die Parameter des Konstruktors werden an sie übergeben. Danach wird die get_age-Methode
aufgerufen um das Alter der Person zu ermitteln und auszugeben.
Abstrakte Datentypen +! erweiterter Inhalt
Ein Abstrakter Datentyp ist ein Verbund von Daten zusammen mit der Definition aller
zulässigen Operationen, die auf sie zugreifen. Es fällt auf, dass die Definition von Abstraktem Datentyp
eine starke Verwandschaft zur objektorientierten Programmierung aufweist. Tatsächlich sind Abstrakte
Datentypen eine starke Motivation zur Verwendung von Klassen und können damit sehr gut umgesetzt
werden. Das ist aber nicht unbedingt so und Abstrakte Datentypen gibt es auch in der klassischen
(nicht objekt-orientierten) Programmierung.
Als Beispiele sollen hier Stack und Queue vorgestellt werden.
Stack / Stapelspeicher
Ein Stack oder Stapelspeicher wird auch als LIFO (Last-In-First-Out) Datenstruktur bezeichnet.
Das letzte eingetragene Element ist das erste ausgegebene.
Im folgenden Programm wird ein Stack verwendet, um einen
Klammernausdruck zu analysieren. Wenn eine öffende Klammer erkannt wird,
dann wird diese im Stack gespeichert. Wenn eine schließende Klammer erkannt
wird, muss sich eine entsprechende öffnende ganz oben im Stack befinden.
Enthält der Ausdruck nur eine Art von Klammer, bräuchte man die Vorgangsweise
mit dem Stack nicht unbedingt, sondern ein Zähler würde genügen, in dem festgehalten
wird, wie viele Klammern geöffnet sind. Der hier gewählte Weg hat den Vorteil,
dass das Verfahren erweiterbar ist auf kompliziertere Ausdrücke und verschiedene
Klammernarten ("()","[]","{}").
Eine Queue oder Warteschlange wird auch als FIFO (First-In-First-Out) Datenstruktur bezeichnet.
Das erste eingetragene Element ist das erste ausgegebene.
Das folgende kleine Programm simuliert einen typischen Anwendungsfall einer
Queue: das Wartezimmer einer Arztpraxis. Jeder neu ankommende Patient wird in
die Warteschlange eingetragen. Die Patienten werden in der Reihenfolge ihres
Eintreffens behandelt.
class Queue:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def enqueue(self, item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
def show(self):
print(self.items)
def neuer_patient_trifft_ein(name):
wartezimmer.enqueue(name)
anzahl = wartezimmer.size()
if anzahl > 10:
nachricht = "Tut mir leid "
nachricht += name
nachricht += " die Wartezeit beträgt mindestens "
nachricht += str(anzahl * 10) + " min."
print(nachricht)
def naechster_patient_ist_dran():
if wartezimmer.size() == 0:
print("Das Wartezimmer ist leer.")
else:
print(wartezimmer.dequeue() + " bitte ins Behandlungszimmer eintreten.")
wartezimmer = Queue()
while True:
print("1: neuer Patient eingetroffen 2: nächster Patient ist dran")
print("3: Zeige Wartezimmer q: Ende")
befehl = input("Bitte wähle eine Option: ")
if befehl == "1":
name = input("Name des eintreffenden Patienten?: ")
neuer_patient_trifft_ein(name)
elif befehl == "2":
naechster_patient_ist_dran()
elif befehl == "3":
wartezimmer.show()
elif befehl == "q":
print("Danke, dass Du MediSoft Wartezimmer-Software verwendet hast.")
break
else:
print("Bitte nur 1, 2, 3 oder 'q' eingeben.")
Fehlerarten
Lexikalische Fehler
Beispiele:
falsch geschriebenes Schlüsselwort
falscher Variablen- oder Funktionsname
falsche Klein-Großschreibung
Programmcode mit einem lexikalischen Fehler ist nicht lauffähig.
Syntaktische Fehler
So ein Fehler liegt vor, wenn zwar alle Wörter richtig geschrieben wurden, aber ein Fehler im Programmaufbau vorhanden ist.
Beispiele:
fehlender Doppelpunkt bei if-, for-, while-Anweisung
falsch gesetzte Klammern
fehlende Zeichen oder falsch verwendete Operatoren
Sprachvergleich
Syntaktische Fehler sind vergleichbar mit Grammatikfehlern. Alle Wörter sind zwar richtig geschrieben doch der Satzbau ist nicht richtig. "Mach deinen Buch zu."
Dieser Fall kann durch eine nur wortbezogene Rechtschreibprüfung nicht gefunden werden aber durch eine grammatikalische Prüfung des Satzes
Auch bei Programmen kann eine Syntaxprüfung durchgeführt werden.
Programmcode mit einem syntaktischen Fehler ist nicht lauffähig.
Semantische Fehler
Alle Wörter sind richtig geschrieben und der Programmaufbau ist korrekt. Ein Programmkonstrukt wurde aber falsch und nicht gemäß
seiner tatsächlichen Bedeutung verwendet. Im Programmcode wird zum Beispiel auf falsche Variablen zugegriffen,
es werden falsche Operationen verwendet, Übergabeparameter werden in der falschen Reihenfolge übergeben. Weitere mögliche Gründe sind:
Verwendung einer Variablen, die nie initialisiert wurde
Division durch 0
Der Zugriff auf eine Liste über ihr Ende hinaus
Unbeabsichtigte Endlosschleifen
Datentypfehler
Sprachvergleich
Wörter sind richtig geschrieben. Sätze sind richtig aufgebaut aber werden nicht in ihrer wirklichen Bedeutung verwendet. Der Satz ergibt keinen Sinn. "Die Uhrzeit ist grün." "Der Hammer isst Gras."
Semantische Fehler sind schwieriger zu finden als syntaktische Fehler. Ein Compiler oder Interpreter kann aber sehr wohl eine semantische Prüfung
enthalten. Programmcode mit einem semantischen Fehler ist lauffähig. Das Programm verhält sich aber nicht wie gewünscht. Es treten Fehler auf.
Eventuell terminiert das Programm ungewollt mit einer Fehlermeldung oder es kommt zu einem Programmabsturz. Eventuell liefert das Programm falsche,
sinnlose Ergebnisse.
Logische Fehler
Ein Programm, das so einen Fehler enthält ist vom Aufbau korrekt. Auch der Programmablauf erfolgt ungestört und es treten keine Fehler auf.
Einziges Problem bei logischen Fehlern ist, dass sie nicht die richtigen Ergebnisse liefern oder dass der Programmablauf anders ist als gewünscht.
Die abweichenden Resultate sind aber nicht sinnlose Werte, wie bei semantischen Fehlern, sie liefern sinnvolle Ergebnisse aber nicht die gewünschten,
weil der Programmierer eine falsche Formel verwendet hat oder diese falsch befüllt zum Beispiel, weil er sich bei der Rangfolge der Operatoren irrt.
Logische Fehler sind Irrtümer des Programmierers.
def mittelwert(a, b):
return a + b / 2 # richtig wäre (a + b) / 2
print(mittelwert(2.0,4.0)) # gewünscht wäre: 3.0 ausgegeben wird: 4.0
print(mittelwert(1.0,4.0)) # gewünscht wäre: 2.5 ausgegeben wird: 3.0
Bei obigem Beispiel sollte der Mittelwert zweier Übergabeparameter berechnet werden, was auch die sinnvolle Benennung andeutet.
Durch einen Fehler des Programmierers wird aber das falsche Ergebnis geliefert.
Sprachvergleich
Wörter sind richtig geschrieben. Sätze sind richtig aufgebaut und alle Begriffe werden in einem sinnvollen Zusammenhang verwendet aber nicht in dem gewünschten.
In folgendem Fall sagt ein englischer Tourist:
"Auf dem Weg hierher habe ich eine Ambulanz gesehen"
und meint dabei einen Rettungswagen (englisch: ambulance), der Zuhörer denkt aber an eine Klinik für medizinische Notfälle.
Logische Fehler können sehr subtil sein und sind dann noch schwieriger zu finden als semantische Fehler.
Programme mit logischen Fehlern sind lauffähig und sie erzeugen keinerlei Fehlermeldungen liefern sinnvolle Ergebnisse aber nicht die gewünschten.
In der folgenden Grafik werden alle Fehlerarten nochmals dargestellt.
Auswirkungen von Fehlern
Oben haben wir die Fehler streng aus Sicht der Programmierung klassifiziert. Jetzt kategorisieren wir sie nach ihren Auswirkungen:
Syntaxfehler
Diese verhindern die Codeausführung.
Egal ob in der Python-Shell oder im IDLE, bei dem Versuch ein Pythonprogramm mit Syntaxfehler zu starten öffnet sich ein Fenster mit einer entsprechenden Meldung und die beanstandete Stelle im Programm wird hervorgehoben.
Laufzeitfehler
Diese werden auch "Bugs" genannt so wie das Insekt. Sie treten während eines Programmlaufs auf. Laufzeitfehler werden oft aber nicht ausschließlich durch semantische Fehler verursacht.
Laufzeitfehler können folgende unerwünschte Auswirkungen haben:
fehlerhafte, sinnlose Resultate
unbeabsichtigte Endlosschleifen. Das Programm reagiert nicht mehr, weil es im Hintergrund nur die Endlosschleife abarbeitet
Ausnahmen (Exceptions)
Absturz (Crash): Das Programm funktioniert nicht mehr und terminiert vorzeitig.
Ausnahmen (Exceptions)
Eine Ausnahme wird vom System zur Laufzeit gemeldet und sie kann durch einen Laufzeitfehler (=Bug) verursacht werden.
Folgende Ausnahme wird durch eine Division durch 0 verursacht:
>>>
Traceback (most recent call last):
File "C:\Python34\error.py", line 10, in
x = 1/0
ZeroDivisionError: division by zero
>>>
Aber Achtung!
Eine Ausnahme kann auch durch eine sogenannte erwartbare Ausnahmesituation verursacht werden. Was ist das?
Nehmen wir folgende Ausnahme als Beispiel.
Sie wurde verursacht, weil eine Datei namens "workfile" aus irgendeinem Grund nicht geöffnet werden konnte:
>>>
Traceback (most recent call last):
File "C:/Python34/file_open.py", line 1, in
f = open('workfile', 'r')
FileNotFoundError: [Errno 2] No such file or directory: 'workfile'
>>>
Das kann aber verschiedene Ursachen haben. Eine falsche Pfadangabe des Programmierers wäre ein Bug.
Falls aber zum Beispiel jemand diese Datei unbeabsichtigt entfernt hat oder vielleicht von dem Speichermedium nicht gelesen werden kann,
dann ist das kein Bug, sondern die oben erwähnte erwartbare Ausnahmesituation.
Erwartbare Ausnahmen kann man aber auch "abfangen". Dabei kann man eine Ausnahmebehandlung durchführen, zum Beispiel kann man den
Benutzer darüber informieren, was nicht funktioniert hat und kann dann kontrolliert terminieren oder man fordert den Benutzer auf
für Abhilfe zu sorgen und versucht dann nochmals die problematische Stelle auszuführen.
Fehlerhafte Resultate
Das Programm scheint zu funktionieren, liefert auch Resultate aber diese entsprechen nicht den Werten in der Spezifikation.
Das könnte an einem logischen Fehler im Programm liegen.
Der Programmablauf erfolgt nicht wie gewünscht
Das Programm erzeugt keine Fehler und liefert keine falschen Ergebnisse aber das beobachtbare Programmverhalten weicht von den Vorgaben ab.
Zum Beispiel erzeugt das Programm Ausgaben wo keine erfolgen sollen und wo sie erfolgen sollten unterbleiben sie.
PyFiddle is a free lightweight Python IDE to run and share Python scripts: https://pyfiddle.io/
We host a growing number of Open Source, interactive textbooks you can use in a course.
Written by award winning authors. Used by some of the best schools: http://interactivepython.org/