LF6 1.1 Python

LF6 1.1 Python

Bild von https://commons.wikimedia.org/wiki/File:Python_molurus_molurus-Portrait.jpg

Allgemeines

Unterschied zwischen Python 2 und Python 3

Python 2 versus Python 3: https://docs.python.org/3/whatsnew/3.0.html

Unterschiede zwischen Python 2 und Python 3: https://wiki.python.org/moin/Python2orPython3

Python-Programm ausführen

Wir möchten ein Pythonprogramm in der Konsole ausführen. Dazu erstellen wir zuerst ein Pythonprogramm (Natürlich könnt Ihr auch einen der vielen Online-Editoren wie https://www.tutorialspoint.com/execute_python_online.php verwenden).

Wir öffnen z.B. nano:

nano hallo.py

und geben ein:

print("Hallo Ferdinand-Braun-Schule")

Zum ausführen können wir eingeben:

python hallo.py

oder aber die Rechte zum ausführen setzen:

chmod u+x hallo.py

Wir müssen in dem Programm noch den Interpreter einstellen:

nano hallo.py

und folgende Zeile ganz oben einfügen:

#!/usr/bin/env python

Das Programm wird mit folgendem Befehl aufgerufen:

./hallo.py 

Variablen

Video: https://youtu.be/TCwIIs_vwzQ?list=PLe2-EUuYYx2dmSq4yQ-AjSbdhFWSceelv

Variablen sind Speicher für Werte wie Zahlen oder Zeichenketten. Wir ändern unser Programm hallo.py so ab, dass es Variablen verwendet:

#!/usr/bin/env python
gruss = "Hallo Ferdinand-Braun-Schule!"
print(gruss)

Aufgabe

Teste folgenden Code:

#!/usr/bin/env python
gruss = "Hallo 'Ferdinand-Braun-Schule!'"
print(gruss)
#!/usr/bin/env python
gruss = 'Hallo "Ferdinand-Braun-Schule!"'
print(gruss)

Zeichen werden immer in “ oder ‘ gesetzt im Gegensatz zu Zahlen:

#!/usr/bin/env python
gruss = "Hallo Ferdinand-Braun-Schule!"
wert = 72
print(gruss)
print(wert)

Namen von Variablen dürfen nicht mit einer Zahl beginnen.

Wert einlesen

Um mit dem Anwender eines Programms zu interagieren, gibt es die Möglichkeit Tastatureingaben in eine Variable einzulesen:

#!/usr/bin/env python
gruss = input("Schreibe einen Gruss: ")
print(gruss)

Zahlen

Python kann auch interaktiv ausgeführt werden. Einfach in die Konsole python eingen:

python
2+5

Ergebnis: 7

a = 2
b = 5
a+b

Ergebnis: 7

Den Wert einer Variable kann man sehen, indem der Name in der Konsole eingegeben wird.

a

Ergebnis: 2

Unterschied zu einem Programm:

nanao zahl.py
a = 2
b = 5
a+b

Das Programm speichern und ausführen.

Ergebnis: Keine Ausgabe!

Die letzt Zeile muss abgeändert werden:

print(a+b)

Ausgabe: 7

Für Zahlen gibt es zwei Variablentypen die meistens verwendet werden: int und float. Int sind natürliche Zahlen (also ohne Komma) und float sind Fließkommazahlen (also mit Komma). Beide Typen gab es bereits bei dem ersten Computer der Welt, der Z1 von Konrad Zuse!

python

a = 2
type(a)

Ergebnis: <class ‘int’>

python
a = 2.23
type(a)

Ergebnsi: <class ‘float’>

a = "2.23"

type(a)

Ergebnis: <class ‘str’>

str steht für Stringund bezeichnet eine Zeichenkette. Der Unterschied ist wichtig, da mit Strings nicht gerechnet werden kann:

python
a = "2"
b = 5
a+b

Ergebnis TypeError

Aber:

python
"2" + "5"

Ergebnis: 25

Strings werden durch das Pluszeichen verbunden!

Programm “alter”

Das Programm soll das Geburtsjahr ausrechnen nachdem das Alter eingegeben wurde. Bitte 2017 durch das aktuelle Jahr ersetzen.

nano alter.py
alter = input("Gebe bitte Dein Alter ein: ")
geburtsJahr = 2017 - alter
print(geburtsJahr)

Ergebnis: TypeError

2017 ist eine Zahl und der Inhalt der Variable alter ein String.

Lösung: Den Typ der Variable alter konvertieren (umwandeln):

geburtsJahr = 2017 - int(alter)

Es können auch Zahlen in einen String umgewandelt werden:

geburtsJahr = str(2017) - int(alter)

Ergebnis: TypeError

Auch eine Umwandlung in Fließkomma ist möglich:

geburtsJahr = 2017 - float(alter)

Ergebnis: Das Ergebnis wird als Fließkommazahl ausgegeben. Python wandelt automatisch den Variiablentyp von 2017 zu float! Damit wird das Ergenis ebenfalls eine Fließkommazahl.

Vergleiche dazu:

float(20)

Ergebnis: 20.0

Strings und Hilfe

Als String werden in Python Zeichen in Anführungsstriche bezeichnet. Es können sowohl “ als auch ‘ verwendet werden.

python
"FBS!"
'FBS!'

Beides sind Strings. Strings können in Vaiablen gespeichert werden:

python
c='FBS'
c

Es ist möglich, Zeichen in einem String zu ersetzen:

python
c='Hallo FBS!'
c.replace('Hallo', 'Salut')

Aufgabe

1.) Speichere das Ergebnis von c.replace(‘Hallo’, ‘Salut’) in einer neuen Variable ab.

2.) Versuche in dem String “Hallo FBS! Alles klar?” den Buchstaben ‘a’ durch ‘b’ zu ersetzen. Werden alle “a” ausgetauscht oder nur das erste “a”?

Einfühung in HTML

Aufgabe

1.) Bitte arbeite folgendes Beispielprojekt durch: https://wiki.selfhtml.org/wiki/HTML/Tutorials/Webprojekte

2.) Es ist an der Zeit eine eigene Website zu erstellen. Entwerfen eine Website über ein Thema Deiner Wahl. Der Inhalt, das Aussehen und die Gestaltung liegt ganz bei Dir mit folgenden Anforderungen:

  • Deine Website muss mindestens vier verschiedene .html-Seiten enthalten. Es sollte möglich sein, von jeder Seite Ihrer Website auf eine andere Seite zu gelangen, indem Sie einem oder mehreren Hyperlinks folgen.

  • Deine Website muss mindestens eine Liste (geordnet oder ungeordnet), mindestens eine Tabelle und mindestens ein Bild enthalten.

  • Deine Website muss mindestens eine Stylesheet-Datei enthalten.

  • Dein Stylesheets muss mindestens fünf verschiedene CSS-Eigenschaften und mindestens fünf verschiedene Arten von CSS-Selektoren verwenden. Du musst den #id-Selektor mindestens einmal und den .class-Selektor mindestens einmal verwenden.

3.) Schaue Dir die Seite form.hmtl an:.

CSS

Wir schauen uns folgenden Quellcode an:

<!DOCTYPE html>
<html>
    <head>
        <title>Meine Webseite!</title>
        <style>
            h1, h2 {
                color: red;
            }
        </style>
    </head>
    <body>
        <h1>Große Überschrift</h1>
        <h2>Kleine Überschrift</h2>
    </body>
</html>

Die Farbe der Überschriften wird rot und zwar für h1 und h2.

Aufgabe

a) Schaue Dir die Datei descendant.html an

b) Füge unten eine unsortierte Liste an (<ul>). Was passiert mit den Farben und warum?

c) Schaue Dir die Datei child.html an. Was hat sich zu descendant.html verändert? Welche Auswirkung hat dies?

d) Schaue Dir die Datei attribute.html an Bei CSS hat bei Überlagerung von Attributen immer das speziellere Vorrang!

e) Schaue Dir die Datei hover.html an Was bedeutet “hover”?

f) Schaue Dir die Datei before.html an Was bedeutet “before”? “\21d2” ist ein Unicode-Element. Für welches Symbol steht es? Wieso wird 3x “Click here” ausgegeben?

g) Schaue Dir die Datei selection.html an Was passiert beim makieren von Text? Warum?

Auflistung der CSS-Selektoren

Github-Pages

Aufgabe

Schaue Dir bitte diesen Artikel an und lege eine “Github-Page” an.

Reponsive Design

Schaue Dir bitte die Datei print.html an. Du siehst auf dem Bildschirm drei Absätze. Wenn Du jetzt aber in die Druckvorschau gehst, siehst Du nur noch zwei Absätze. Der letzte Absatz ist ausgezeichnet mit “screen-only” und wird daher nicht ausgedruckt!

Schaue Dir bitte die Datei responsive0.html an.. Wir sehen, dass über das @media-Attribut die Farbe in Abhängigkeit von der Breite des Festers eingestellt wird.

Bei dem Beispiel in der Datei responsive1.html wird die Überschrift in.Abhängigkeit der breite des Fensters angepasst. Darüber gibt es die Zeile mit dem Befehl Vieport. Es ist sinvoll, eine Webseite mit diesem Befehl anzufangen. Der Befehl passt die Schriftgrösse an die Auflösung des Zielgeräts an und verhindert damit, dass auf einem hochauflösendem Monitor der Text so.klein dargestellt wird, dass er nicht mehr gelesen werden kann.

Flexbox

Eine weitere Möglichkeit ist der Einsatz von Flexbox. Flexbox ermöglcht viereckige Textfelder die je nach Größe des Bildschirms unterschiedlich angeordnet werden. Als Beispiel schauen wir uns die Datei responsive1.html an. Die Magie liegt in den Zeilen 8 und 9 (Display: flex umd der nachfolgenden Zeile.)

Auch Tabellen können sich in der Größe anpassen. Hier die Datei grid.html. In.Zeile 13 wird die Weite der einzelnen Spalten angegeben: 200 Pixel für die beiden ersten und “auto” für die letzt Spalte. Stze zum ausprobieren alle Breiten auf “auto”.

Aufgabe

1.) Dein Stylesheet muss mindestens eine auf Mobilgeräte reagierende @media-Abfrage enthalten, sodass sich bei kleineren Bildschirmen etwas am Styling ändert.

2.) Du musst Bootstrap 4 auf Ihrer Website verwenden, indem Sie mindestens eine Bootstrap-Komponente verwenden und mindestens zwei Bootstrap-Spalten für Layoutzwecke verwenden, indem Sie das Rastermodell von Bootstrap verwenden.

3.) Deine Stylesheets müssen mindestens eine SCSS-Variable, mindestens ein Beispiel für SCSS-Verschachtelung und mindestens eine Verwendung von SCSS-Vererbung verwenden.

4.) Geben in der README.md eine kurze Beschreibung ein, die Dein Projekt beschreibt, was in jeder Datei enthalten ist und (optional) weitere zusätzliche Informationen.

Flask

Erstmal ein Schritt zurück

name = input()
print(f"Hallo {name}!")

Dieses Skript funktioniert erst ab Python 3.6! Hier ein guter Artikel über die neue Funktion. Einfach ausgedrückt, weißt das f vor den Anführungsstrichen print an den String in geschweiften Klammern als Variable zu lesen und diesen durch den Inhalt der selbigen zu ersetzen.

Wir schreiben jetzt ein Programm, dass uns sagt ob eine Zahl positiv oder negativ ist:

x = 100
if x > 0:
   print("Die Zahl ist positiv!")
elif x < 0:
   print("Die Zahl ist negativ!")
else:
   print("Die Zahl ist 0!")

Dem Befehl if folgt eine Bedingung und ist diese wahr werden die eingerückten Zeilen ausgeführt. Ist die erste Bedinung falsch wird elif ausgeführt, ist if wahr wird die Zeile elif nicht ausgeführt. Ist sowohl die Aussage vo if und elif falsch, wird else ausgeführt. Ist if oder elif wahr, dann wird else nicht mehr ausgeführt.

Sequenzen

Eine der Stärken von Python ist die Verbeitung von Sequenzen (Zeichenketten bzw. Datenreihe):

name = "Ferdinand"
koordinaten = (10.0, 30.0)
namen = ["Ferdinand", "Bob", "Charlie"]

Wir geben die Zuweisung zur Variable name in der Cli ein:

name = "Ferdinand"

Der Zugriff auf jedes einzelne Zeichen erfolgt über einen sogenannten Index:

>>> name[0]
'F'
>>> name[1]
'l'

Ebenso verhält sich bein den Koordinaten:

>>> koordinaten = (10.0, 30.0)
>>> kooridnaten[0]
10.0
>>> koordinaten[1]
20.0

Genauso verhält es sich bei der Variable namen:

>>> namen = ["Ferdinand", "Bob", "Charlie"]
>>> namen[0]
'Ferdinand'
>>> namen[1]
'Bob'
>>> namen[2]
'Charlie'

Aufgabe

Welche Ausgabe erscheint bei namen[3] und warum?

Schleifen

for i in range(5):
    print(i)

Führe den Code aus. range(5) beinhaltet alle Zahlen von 0 bis 4.

Aufgabe

Ändere das Programm so ab, dass alle Zahlen von 0 bis 9 ausgegeben werden.

Ausgabe von Listen:

namen = ["Ferdinand", "Bob", "Charlie"]
for name in namen:
    print(name)

Aufgabe

Müssen die Variablen immer den gleichen Typ haben?

Set

s = set()
s.add(1)
s.add(3)
s.add(5)
s.add(3)
print(s)

Set ist eine unsortierte Liste von einzigartigen Elementen. Siehe auch hier.. Aufgrund der Einzigartigkeit wird die letzte 3 nicht im set aufgenommen!

Dictionary

Wir schauen uns die Datei dictionaries.py an. Was passiert? Kannst Du Dir die Ausgabe erklären?

Funktionen

Wir schauen uns die Datei functions.py an. Was passiert? Kannst Du Dir die Ausgabe erklären?

Es ist auch möglich, dass Funktionen von anderen Programmen importiert werden:

modules.py

Hier importiert das Programm modules.py die Funktion square() aus der Datei functions.py.

Es wird jetzt leider das ganze Programm abgearbeitet. Um das zu verhindern, definiert man meistens eine Funktion mit der Bezeichnung main().

def square(x):
    return x * x

def main():
    for i in range(10):
        print("{} squared is {}".format(i, square(i)))

Das Problem ist jetzt, dass beim Aufruf von module.py die Ausgabe korrekt ist aber nicht die Datei functions.py nicht mehr direkt gestartet werden kann. Das korrigeren wir mit einer magischen Zeile:

def square(x):
    return x * x

def main():
    for i in range(10):
        print("{} squared is {}".format(i, square(i)))

if __name__ == "__main__":
      main()

Class

Ein Beispiel findet sich in der Datei classes.py. Wir legen einen neuen Typ für Variablen an, den wir Point nennen. Der Typ besteht aus zwei Zaheln, die durch Komma getrennt werden. Die erste Zahl wird x ganannt und die zweite Zahl y.

Flask installieren

Mit

apt install python3-pip
pip3 install flask

installieren wir Flask in unsere Python-Umgebung.

Installation in der Schulumgebung

Eine Installation in der Schulumgebung gestalltet sich immer schwieriger als zu Hause:

conda config --set ssl_verfify False

Vollzugriff rekuriv für c:\ProgramData\Anaconda3 für den Benutzer geben.

Und dann:

conda install -c anaconda flask 

in die Anaconda-Shell eingeben

Testen

Wir kopieren die Datei app.py in unserer Arbeitsverzeichnis. Als nächstes führen wir folgenden Befehl aus, wenn wir über 127.0.0.1:5000 auf das Ergebnis zugreifen möchten:

flask run

Möchten wir den Server public frei geben.

Achtung: Flask ist nicht für den produktiven Einsatz geeignet. Weder von der Perfomance noch von der Sicherheit !!!:

flask run --host=0.0.0.0

Dann öffnen wir entweder unseren lokalen Browser oder einen Online-Browser (weil Port 5000 im Schulnetz gesperrt ist) und sollten ein fröhliches Hallo Welt sehen.

Woher weiß Flask welches Programm gestartet werden muss? Dafür setzt man eine Umgebungsvariable:

export FLASK_APP=application.py

Schaue Dir bitte folgende Datei an und versuche sie zu verstehen:

Hilfe

Die Übersicht der Befehle zur manipulation von Strings ist vielfältig. Mit dem Befehl

python
dir(c)

bekommt man einen ersten Überblick über die Möglichkeiten.

Ein Beispiel:

python
c.upper()

Um Hilfe zu einem Befehl zu bekommen, kann der help-Befehl verwendet werden:

python
help("".replace)

Es kann auch verwendet werden:

python
help(c.replace)

Parameter in der Hilfe in eckigen Klammern sind optional.

Aufgabe

Ersetze im String “Hallo FBS! Alles klar?” nur das erste ‘a’ durch ein ‘b’.

Indizierung von Zeichenketten

Strings ist ein komplexer Datentyp, der sich aus vielen Variablen zusammen setzt mit jeweils einem Zeichen (char). Daher ist es möglich, jedes Zeichen in einem String einzeln anzusprechen (Stichwort Array von Chars):

python
c="Hallo Welt!"
c[4]

Wir fangen immer bei 0 an zu zählen.

Aufgaben

1.) Schreibe einen Befehl, der das letzt Zeichen “!” ausgibt.

2.) Welche Ausgabe erfolgt bei c[-1] und c[-2]?

Um Zeichenketten zu extrahieren, können die Start und End-Position in die Eckige Klammer eingetragen werden. Wir möchten “Ha” extrahieren:

c="Hallo Welt!"
c[0:1]

Die Ausgabe ist “H”. Das liegt daran, dass beim auftrennen von Strings immer die Stelle des Schnitts angegeben wird also das Ergebnis immer ein Zeichen zu wenig hat.

c="Hallo Welt!"
c[0:2]

Aufgabe

Teste die Ausgabe von c[-4:-1]. Erhälst Du das erwartete Ergebniss?

Listen

Listen speichern mehrere Elemente in einer Variable, ähnlich einer Einkaufsliste die mehrere Eintragungen hat. Das Kennzeichen einer Liste sind die eckigen Klammern mit den Elementen:

c=["Ferdinand Braun", 1850, 1918,"Physiker"]

Jedes Element lässt sich einzeln ansprechen:

c[0]

Ausgabe:

‘Ferdinand Braun’

Jedes Element hat seinen eigenen Variablentyp:

type(c[0])
type(c[1])

Aufgabe

  1. Welches Ergebnis kommt bei c[:2] heraus?

  2. Welchen Variablentyp hat der Listen-Abschnitt?

  3. Schaue Dir die Verfügbaren Optinen von “list” mit dir an.

  4. Füge mit dem Befehl c.append() “Nobelpreistraeger” an das Ender der Liste an.

  5. Schaue Dir mit dem Befehl help(c.remove) den Befehl remove an.

  6. Entferne “Physiker” aus der Liste.

TUPELS

Tupels sind ähnlich zu Listen aber es ist kein schreibender Zugriff möglich. Wir definieren ein Tupel analog zu einer Liste:

t = ("Hallo", 1, 2.3)

Greifen lesend auf einzelne Elemente zu:

t[-1]

Ausgabe: 2.3

Aufagbe

Vergleich die möglichen Befehle auf die Objekte tupel und list. Was fällt Dir auf? Vergleiche bitte mit dem Befehl dir(list) bzw. dir(tuple).

Dictonary

Dictonary ordnen Begriff paarweise einander zu:

d = {"boy":"Junge", "girl":"Mädchen"}

Bei einem Dictonary wird unterschieden zwischen einem Schlüssel (Key) und Wert (value). In dem Beispiel sind die englischen Wörter die Schlüssel und die deutschen Wörter die Werte.

Wir greifen auf die Werte über die Schlüssel zu:

d["boy"]

Ausgabe: ‘Junge’

Die Abfrage ist nur in die Richtung Key -> Value möglich und nicht in die andere Richtung.

Der Rückgabewert kann auch eine Liste sein:

d = {"boy":"Junge", "girl":"Mädchen", "eat":("frisst", "isst"), "have":("haben","bin","besitze")}

Ausgabe:

 d["have"]
 ('haben', 'bin', 'besitze')

Bei der Liste kann dann auch auf einzelne Elemente zugegriffen werden, wie wir es oben bereits bei den Listen gesehen haben:

 >>> d["have"][1]
'bin'

Aufgabe

Bitte fürhre diesen Test durch:

http://fachinformatiker-fulda.de/index.php/2017/09/18/quiz-python-1/ Du solltest 100% erreichen!

Funktionen

Funktionen werden eingesetzt um ein Programm zu strukturieren und/oder öfter benötigten Programmcode nur an einer Stelle vorzuhalten. Funktionen werden mit dem Wort def gefolgt vom Funktionnamen gekennzeichnet. Sie werden beim starten des Pythonprogramms erstbei aufruft über den Funktionsnamen ausgeführt. Wir verwenden viele in Python eingebaute Funktionen bereits wie z.B. print() oder input(). Wir programmieren als Beispiel einen Währungsumrechner. Der Umrechner soll Euro in die polnische Währung Zloty umrechnen. Wir benötigen dazu zwei Angaben: dem Umrechnungskurs und die Menge an Euros die umgerechnet werden soll. Momentan liegt der Umrechnungsfaktor bei 4,3: 1 Euro ist also 4,3 Zloty wert. Bitte überprüfe den Wert. Werte werden Funktionen mit Hilfe sogeannter Parameter übergeben, die in Klammern geschrieben werden. Mit dem Befehl return wird das Ergebnis der Funktion zurück gegeben an die aufrufende Stelle. Wenn wir das Programm ausführen, werden wir keine Ausgabe erhalten, weil die Funktion nicht aufgerufen wird.

def waehrungsrechner(kurs, euro):
    zloty = euro*kurs
    return zloty

Wir ergänzen das Programm um einen Funktionsaufruf. Wir möchten 100 Euro umtauschen:

def waehrungsrechner(kurs, euro):
    zloty = euro*kurs
    return zloty
    
print(waehrungsrechner(4.3,100))    

Fehler

Fehler sind meschlich und nicht schlimm. Es kommt nur drauf an mit Ihnen sinnvoll umzugehen. Ferler werden auch Error oder Bug genannt. Die Bezeichnung Bug kommt daher, dass bei den Computern füher sich kleine Tiere zwischen den elektrischen Kontakten ihr Leben aushauchen konnten und so die Funktionsfähigkeit des Computers beeinträchtigten (siehe z.B. hier: https://de.wikipedia.org/wiki/Programmfehler#/media/File:H96566k.jpg oder auch https://de.wikipedia.org/wiki/Programmfehler)

In Python gibt es 3 Kategorien von Fehlern: Logische Fehler, Syntax-Fehler und Ausführungsfehler (Exception). Wir konzentrieren uns zuerst auf die Syntax-Fehler, die den größten Teil darstellen. Dazu ein Programm mit dem tollen Namen fehler.py:

print("1")
int(10)
int 9
print(2)
print "FBS"

Ausgabe:

Traceback (most recent call last):
  File "fehler.py", line 3
    int 9
        ^
SyntaxError: invalid syntax

Die zweite Zeile teilt uns den Namen der betroffenden Datei mit, in diesem Fall fehler.py.

Syntaxfehler

Der Fehler beruht darauf, dass int() eine Funktion ist und damit die Argumente in Klammer geschrieben werden. Wir korrigieren Die Zeile und führen das Programm erneut aus.

print("1") 
int(10) 
int(9) 
print(2) 
print "FBS" 

Wir treffen auf den nächsten Fehler (die Anzeige hier stammt von QPython unter Android):

File "/storage/emulated/0/qpython/.last_tmp.py", line 5 
print "FBS" 
          ^ SyntaxError: invalid syntax 

Wir sehen an der veränderten Zeilennummer, dass der vorhergehende Fehler behoben wurde. Print ist ebenfalls eine Funktion und muss daher in Klammern geschrieben werden. Bei der ausführung unter Anaconda wird direkt auf die fehlenden Klammern hingewiesen.

Wir korrigieren auch diesen Fehler:

print("1") 
int(10) 
int(9) 
print(2) 
print("FBS") 

und das Programm läuft fehlerlos durch:

1 
2 
FBS 

Wir bauen noch einen Fehler in das Programm ein:

print("1") 
int(10) 
int(9) 
print(2) 
print("FBS") 
a = [2,3,4) 

Das Programm erzeugt bei Ausführung einen Fehler:


File "/storage/emulated/0/qpython/.lasttmp.py", line 6 
a = [2,3,4) 
          ^ SyntaxError: invalid syntax 
1|u0a76@sofia3gr:/ $

Der Fehler ist leicht zu beheben:

print("1") 
int(10) 
int(9) 
print(2) 
print("FBS") 
a = [2,3,4] 

Und das Programm läuft problemlos durch.

Wir ändern das Programm nochmals ab:

print("1") 
a = 1 
b = "2" 
print(int(2) 
print("FBS") 
print(a+b) 

Und wir bekommen eine Fehlermeldung:

File "/storage/emulated/0/qpython/.lasttmp.py", line 5 
print("FBS") 
^ SyntaxError: invalid syntax 1|
u0a76@sofia3gr:/ $ 

In der Zeile 5 ist aber kein Fehler. Der Fehler ist in Zeile 4. Dort wurde vergessen, eine Klammer zu schließen. Python fällt das aber erst in der nächsten Zeile auf, weil für den Interpreter völlig überraschend ein weiterer Befehl kommt, der nicht in den Kontext passt.

print("1") 
a = 1 
b = "2" 
print(int(2)) 
print("FBS") 
print(a+b) 

Syntaxfehler gehören meist zu den einfach zu behebenen Fehlern. Meistens ist der Fehler an der angegebenen Stelle. Selten kann es vorkommen, dass der Fehler eine Zeile vorher entsteht.

Python überprüft vor der Ausführung den Quellcode auf Syntaxfehler, erst danach wird das Programm ausgeführt und es kann zu Ausführungsfehlern kommen.

Ausführungsfehler

Wir führen das Programm von oben aus und treffen bekommen eine weitere Fehlermeldung:

1 
2 
FBS 
Traceback (most recent call last): 
File "/storage/emulated/0/qpython/.lasttmp.py", line 6, in <module> 
print(a+b) 
 TypeError: unsupported operand type(s) for +: 'int' and 'str' 1|
 u0a76@sofia3gr:/ $ 

Wir sehen an der Ausgabe, dass das Programm bereits zum Teil abgearbeitet worden ist. Auch der Hinweis auf einen Syntaxfehlers fehlt. Beides Hinweise auf einen Ausführungsfehler. Das bedeutet, dass die Syntax eingehalten worden ist und ein Problem der Variablenwerte vorliegt. Die Meldung gibt uns auch den entsprechenden Hinweis.

Wir korrigieren das Programm:

print("1") 
a = 1 
b = 2 
print(int(2)) 
print("FBS") 
print(a+b) 

Es gibt noch viele andere Ausführungsfehler neben dem Ty-Fehler. Ein weiterer häufiger Fehler ist der Bezeichner-Fehler (name error):


print("1") 
a = 1 
b = 2 
print(int(2)) 
print("FBS") 
print(a+c) 

Bei der Ausführung bekommen wir den Hinweis:


1 
2 
FBS 
Traceback (most recent call last): 
File "/storage/emulated/0/qpython/.lasttmp.py", line 6, in <module> 
print(a+c) 
NameError: name 'c' is not defined 1|
u0a76@sofia3gr:/ $ 

Python kann zum Zeitpunkt der Ausführung die Variable c nicht ansprechen. Es kann durchaus sein, dass die Variable später existiert oder in einem lokalen Kontext. Zum Zeitpunkt der Ausführung der Zeile 6 existiert die Variable aber nicht!

Ein weiter beliebter Ausführungsfehler ist der einer nicht definierten mathematischen Berechnung.

print("1") 
a = 1 
c = 0 
print(int(2)) 
print("FBS") 
print(a/c) 

Es kommt zu folgender Fehlermeldung:

1 
2 
FBS 
Traceback (most recent call last): 
File "/storage/emulated/0/qpython/.lasttmp.py", line 6, in <module> 
print(a/c) 
ZeroDivisionError: division by zero 1|
u0a76@sofia3gr:/ $ 

Zahlenraten

Wir schreiben unser erstes eigenes Programm: Zahlenraten

Der Computer denkt sich eine Zahl zwischen 0 und 100 aus. Der Mensch soll die Zahl erraten und hat die Möglichkeit die Zahl mit 6 Versuchen zu erraten. Der Computer kennt drei Reaktionen auf eine Eingabe: “Meine Zahl ist größer!”, “Meine Zahl ist kleiner!” und “Gewonnen!”. Durch geschicktes raten sollte es möglich sein, jede Zahl mit 6 Versuchen zu erraten.

Wir verwednen dafür die Testgetriebene Entwicklung (TDD, vgl. https://de.wikipedia.org/wiki/Testgetriebene_Entwicklung) und legen 2 Dateien an mit den Namen test.py und zahlenraten.py

Die Datei test.py führt sogenannte Unity Tests aus auf die Dateie zahlenraten und gibt uns Rückmeldung ob die Funktionen der Datei ordnungsgemäß arbeiten. Später können die Unity Test durch automatisierte Verfahren automatisch nach Codeänderungen ausgeführt werden und verhindern so, dass sich durch nachträglich Veränderungen am Quellcode Fehler eingeschlichen haben.

test.py:

import unittest
from zahlenraten import ueberpruefung
class zahlenraten_ueberpruefung(unittest.TestCase):
    pass
    
if __name__ == "__main__": 
    unittest.main()

Wir importieren zuerst die Klasse Unittest, die die entasprechende Befehle für einen Test bereitstellt und wir importieren in der zweiten Zeile den zu testenden Programmcode.In der dritten Zeile erstellen wir eine Klasse (was immer das ist), die den Programmcode dann testet.

Die Datei zahlenraten.py:

def ueberpruefung(eingabe, testwert):
    pass

def zufallszahl():
    pass

zahl = zufallszahl()

eingabewert = input("Bitte eine Zahl eingeben: ")
ueberpruefung(eingabewert)    

    
print("Das Spiel ist zu Ende")    

Wir definieren eine Funktion ueberpruefung mit 2 Parametern: eingabe und testwert. Die Funktion macht noch überhaupt nichts, pass bedeutet: “nichts machen”. Ebenso bei der Funktion zufallszahl. Die erste Zeile, die beim start des Programms ausgeführt wird ist “zahl=zufallszahl” in der die Funtkion Zufallszahl aufgerufen wird und das Ergebnis nach zahl gespeichert wird.

Die nächste Zeile fordert den Benutzer zu einer Eingabe auf und speichert diese in die Variable eingabewert ab. Danach wird die Funktion ueberpruefung aufgerufen, die später die Ausgabe “größer”, “kleiner” oder “treffer” ausgeben soll.

Die letzte Zeile zeigt uns an, dass das Programm bis zum Ende abgearbeitet worden ist.

Wir definieren jetz einen Test um in der Funktion ueberpreuefung negative Zahlen abzufangen:

import unittest
from zahlenraten import ueberpruefung
class zahlenraten_ueberpruefung(unittest.TestCase):
    
    def testCalculation(self):
        """Wird eine negative Zahl abgelehnt?"""
        for index in range(-1, -10, -1):
            self.assertFalse(ueberpruefung(index))
            
if __name__ == "__main__": 
    unittest.main()

Der Test schlägt natürlich Fehl, da wir noch nichts programmiert haben:

Bitte eine Zahl eingeben: 1
Das Spiel ist zu Ende
.
----------------------------------------------------------------------
Ran 1 test in 0.002s

OK
Traceback (most recent call last):
  File "/home/pi/python/test.py", line 11, in <module>
    unittest.main()
  File "/usr/lib/python3.5/unittest/main.py", line 94, in __init__
    self.runTests()
  File "/usr/lib/python3.5/unittest/main.py", line 257, in runTests
    sys.exit(not self.result.wasSuccessful())
SystemExit: False

Was ist der einfachste Weg, den Test zu erfüllen? Genau, wir geben ein False zurück:

def ueberpruefung(eingabe, testwert):
    return False

def zufallszahl():
    pass

zahl = zufallszahl()

eingabewert = input("Bitte eine Zahl eingeben: ")
ueberpruefung(eingabewert, zahl)    

    
print("Das Spiel ist zu Ende") 

Und wir bekommen einen positiven Testdurchlauf:

>>> %Run test.py
Bitte eine Zahl eingeben: 1
Das Spiel ist zu Ende
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Manche Editoren geben leider auch einen Trace zurück, wenn kein Fehler aufgetreten ist. Dies können wir unterbinden, indem wir die letzten beiden Zeilen durch diesen Code ersetzen:

if __name__ == "__main__": 
    try:
        unittest.main()
    except SystemExit as inst:
        if inst.args[0] is True: 
            raise

Damit wird nur im Fehlerfalle ein Trace ausgegeben. Dieses verhalten zeigt das Programm auch beid er Ausführung innerhalb der Konsole.

Wir testen jetzt, ob Zahlen größer 100 abgelehnt werden. Das schöne ist, dass wir hier ebenfalls ein False als Rückgabewert erwarten.

import unittest
from zahlenraten import ueberpruefung
class zahlenraten_ueberpruefung(unittest.TestCase):
    
    def testCalculation(self):
        """Wird eine negative Zahl abgelehnt?"""
        for index in range(-1, -10, -1):
            self.assertFalse(ueberpruefung(index))
        """Wird eine Zahl größer 100 abgelehnt"""
        self.assertFalse(ueberpruefung(101))
        
# Diese komplizierte Struktur ermöglicht es auch bei IDEs, die immer einen Trece ausgeben, diesen zu unterbinden, wenn kein Fehler aufgetreten ist.        
if __name__ == "__main__": 
    try:
        unittest.main()
    except SystemExit as inst:
        if inst.args[0] is True: 
            raise

Und wir bekommen wieder einen positiven Durchlauf:

>>> %Run test.py
Bitte eine Zahl eingeben: 1
Das Spiel ist zu Ende
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Jetzt überprüfen wir die Zahlen zwischen 0 und 100, die ein True zurückgeben sollen:

import unittest
from zahlenraten import ueberpruefung
class zahlenraten_ueberpruefung(unittest.TestCase):
    
    def testCalculation(self):
        for index in range(-1, -10, -1):
            self.assertFalse(ueberpruefung(-10))
        print("Negative Zahlen")

        self.assertFalse(ueberpruefung(101))
        print("Zahlen größer 100")
    
        for index in range(1, 100, 1):
            self.assertTrue(ueberpruefung(1))
        print("Zahlen zwischen 0 und 100")
# Diese komplizierte Struktur ermöglicht es auch bei IDEs, die immer einen Trece ausgeben, diesen zu unterbinden, wenn kein Fehler aufgetreten ist.        
if __name__ == "__main__": 
    try:
        unittest.main()
    except SystemExit as inst:
        if inst.args[0] is True: 
            raise

Jetzt müsste eigentlich ein Fehler gemeldet werden und er wird auch angezeigt:

import unittest
from zahlenraten import ueberpruefung
class zahlenraten_ueberpruefung(unittest.TestCase):
    
    def testCalculation(self):
        for index in range(-1, -10, -1):
            self.assertFalse(ueberpruefung(index))
        print("Negative Zahlen")

        self.assertFalse(ueberpruefung(101))
        print("Zahlen größer 100")
    
        for index in range(1, 100, 1):
            self.assertTrue(ueberpruefung(index))
        print("Zahlen zwischen 0 und 100")
# Diese komplizierte Struktur ermöglicht es auch bei IDEs, die immer einen Trece ausgeben, diesen zu unterbinden, wenn kein Fehler aufgetreten ist.        
if __name__ == "__main__": 
    try:
        unittest.main()
    except SystemExit as inst:
        if inst.args[0] is True: 
            raise

Und hier der Fehler:

Bitte eine Zahl eingeben: 1
Das Spiel ist zu Ende
Negative Zahlen
Zahlen größer 100
F
======================================================================
FAIL: testCalculation (__main__.zahlenraten_ueberpruefung)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/pi/python/test.py", line 14, in testCalculation
    self.assertTrue(ueberpruefung(index))
AssertionError: False is not true

----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (failures=1)
Traceback (most recent call last):
  File "/home/pi/python/test.py", line 19, in <module>
    unittest.main()
  File "/usr/lib/python3.5/unittest/main.py", line 94, in __init__
    self.runTests()
  File "/usr/lib/python3.5/unittest/main.py", line 257, in runTests
    sys.exit(not self.result.wasSuccessful())
SystemExit: True

Wir passen unser Programm entsprechend an:

def ueberpruefung(eingabe):
    if 0<= eingabe <=100:
        return True
    else:
        return False

def zufallszahl():
    pass

zahl = zufallszahl()

eingabewert = input("Bitte eine Zahl eingeben: ")
ueberpruefung(eingabewert)    

    
print("Das Spiel ist zu Ende")    

Wir bekommen nun eine Fehlermeldung:

Bitte eine Zahl eingeben: 1
Traceback (most recent call last):
  File "/home/pi/python/test.py", line 2, in <module>
    from zahlenraten import ueberpruefung
  File "/home/pi/python/zahlenraten.py", line 13, in <module>
    ueberpruefung(eingabewert)
  File "/home/pi/python/zahlenraten.py", line 2, in ueberpruefung
    if 0<= eingabe <=100:
TypeError: unorderable types: int() <= str()

Der Fehler leigt daran, das der befehl input immer einen String einliest. Den Fehler verbessern wir jetzt indem wir den Typ umwandeln:

def ueberpruefung(eingabe):
    if 0<= eingabe <=100:
        return True
    else:
        return False

def zufallszahl():
    pass

zahl = zufallszahl()

eingabewert = input("Bitte eine Zahl eingeben: ")
eingabewert = int(eingabewert)
ueberpruefung(eingabewert)    

    
print("Das Spiel ist zu Ende")    

Wir geben beim start des Programms einen Buchstaben ein und das Programm stürzt ab:

>>> %Run zahlenraten.py
Bitte eine Zahl eingeben: m
Traceback (most recent call last):
  File "/home/pi/python/zahlenraten.py", line 13, in <module>
    eingabewert = int(eingabewert)
ValueError: invalid literal for int() with base 10: 'm'

Wir führen die Typumwandlung in der Funktion überprüfen aus um den Fehler abzufangen. Dafür schreiben wir erst eine Testfunktion:

import unittest
from zahlenraten import ueberpruefung
class zahlenraten_ueberpruefung(unittest.TestCase):
    
    def testCalculation(self):
        for index in range(-1, -10, -1):
            self.assertFalse(ueberpruefung(index))

        self.assertFalse(ueberpruefung(101))
    
        for index in range(1, 100, 1):
            self.assertTrue(ueberpruefung(index))
        
        self.assertFalse(ueberpruefung("m"))
# Diese komplizierte Struktur ermöglicht es auch bei IDEs, die immer einen Trece ausgeben, diesen zu unterbinden, wenn kein Fehler aufgetreten ist.        
if __name__ == "__main__": 
    try:
        unittest.main()
    except SystemExit as inst:
        if inst.args[0] is True: 
            raise

Jetzt passen wir das Programm an, damit kein Fehler mehr auftritt:

def ueberpruefung(eingabe):
    try:
        eingabe = int(eingabe)
        if 0<= eingabe <=100:
            return True
        else:
            return False
    except ValueError:
        return False
    

def zufallszahl():
    pass

zahl = zufallszahl()

eingabewert = input("Bitte eine Zahl eingeben: ")
ueberpruefung(eingabewert)    

    
print("Das Spiel ist zu Ende")    

Schreibe eine Testfunktion, dass die Funktion zufallszahl nur Zahlen zwischen 0 und 100 liefert. Schreibe dann die Funktion zufallszahl.

Schreibe eine Funktion auswertung, die feststellt ob die eingegebene Zahl größer, kleiner oder gleich der Zufallszahl ist. Die Funktion wird mit 2 Parametern aufgerufen: eingegebene Zahl und die Zufallszahl. Selbstverständlich schreiben wir zuerst einen test.

Wir setzen die Zeile mit dem Befehl input in eine geeignete Schleife, so dass diese maximal 10 mal durchlaufen wird. Wurde die Zahl erraten, wird die Schleife mit einer entsprechenden Meldung beendet. Wird die maximale Zahl überschritten, kommt ebenfalls eine entsprechende Meldung.

Schleifen

Es gibt einmal die “for-Schleife” und auf der anderen Seite die “while-Schleife”. Die “for-schleife” ist dafür gedacht, bestimmte Befehle n mal auszuführen. N ist bei Eintritt in die Schleife ein fester Wert. Die “While-Schleife” wird verwendet um einen Code-Block solange auszuführen, solange eine Bedingung wahr ist.

Projekt

Wir haben viele Datenbank-Server und möchten ein einfaches Tool, dass diese entweder lokal oder nach S3 sichert. Es sind folgende Schritte notwendig:

  • Eine Datenbank-URL muss angegeben werden.
  • Ein Treiber für “lokal” oder “s3” muss angegeben werden
  • Ein Ziel muss angegeben werden. Die Interpretation ist abhängig vom Treiber: Pfad oder Name des S3-Bucket.

1. Aufgabe

a) Mit Welchem UML-Diagramm kann obige Anforderung beschrieben werden?

b) Wähle ein Tool aus, dass kostenfrei ist und mit dem das Diagramm gezeichnet werden kann.

c) Zeichne das Diagramm und gebe als Bild in Moodle ab.

2. Aufgabe

Schreibe bitte alle verwendeten Befehle auf:

a) Installiere eine PostgreSQL-Datenbank mit entsprechenden Client.

b) Lade Die entsprechende Datenbank von http://sportsdb.org/sd/samples herunter.

c) Importiere die Datei in die Datenbank

Ist es möglich, die Installation zu automatisieren? Mache Dir hierzu Gedanken! Wie weit kommst Du mit Deinem jetzigen Wissen? Begründe diese und gebe die Antwort un Moodle ab!