Sie sind auf Seite 1von 33

PROGRAMMIEREN EINFÜHRUNG IN PYTHON

Benjamin Klebel Nachhilfekurse Stracke Beethovenplatz 1, 1010 Wien

1

1

TABLE OF CONTENTS

 

2

Wie dieses Skriptum funktioniert

4

3

Grundlegendes

 

5

3.1

Wie arbeiten Programme? (Interpreter vs compiled)

5

3.2

Ein erstes Programm

6

3.3

Vorsicht! – eins nach dem anderen…

7

3.4

Kommentieren Kommentieren Kommentieren…

8

3.5

* Verbotene Namen *

8

4

Datentypen

 

9

4.1 Verschiedene Datentypen im überblick

9

4.2 Kollektionen

10

4.3 String

 

11

4.4 Liste

11

4.5 Dictionary

12

4.6 Aufpassen bei Kollektionen!

12

5

Fallunterscheidungen if

13

6

* Python Syntax: „context“ („context manager”) *

14

 

6.1

* Dateioperationen mit dem Context Manager *

14

7

Schleifen

 

14

7.1

Die

„for“ Schleife

15

7.2

Die

„while“ Schleife

16

7.3

Nützliche spezielle Schleifenoperatoren

16

7.4

* Praktische Hinweise zu Schleifen *

17

8 Funktionen

18

9 Lesen und Schreiben von Dateien

19

10 Ausnahmebehandlung (Exception Handling)

20

10.1

Behandlung von mehreren Fehlern

20

10.2

„else“ und „finally“

21

10.3

„raise“

21

10.4

*Zusätzliches*

21

11 Objektorientierte Programmierung

22

11.1

Klassen

23

11.1.1 dynamische Attribute

23

11.1.2 Methoden

24

11.1.3 Konstruktor und „magic“

24

11.1.4 Docstrings

25

11.1.5 Statische Attribute

25

11.2

Vererbung

26

11.2.1 Grundlagen

26

11.2.2 Ausführung in python

27

11.2.3 Feinheiten

27

11.3

Private Attribute und Datenkapselung

28

11.3.1

Grundsätzliches

28

11.3.2

Ausführung in python

28

11.3.3

„set“ und „get“ Methoden

29

11.3.4

* „programming guidelines“ für python – Kritische Betrachtung * .30

11.4 Abstraktion

2

30

11.5

Polymorphismus

31

15 Graphische Benutzeroberfläche

33

12 Schnittstellen zum Betriebssystem

32

16 Netzwerkkommunikation

33

13 Testen

33

17 Software Engineering - Theorie

33

14 Datenspeicherung

33

3

2

WIE DIESES SKRIPTUM FUNKTIONIERT

Auf der linken Seite findest du Beschreibungen, auf der rechten Seite gibt es zumeist Codebeispiele und/oder Illustrationen.

Absätze die kursiv gehalten werden, wie hier, sind zusätzliche Kommentare, die äußerst wahrscheinlich nicht notwendig für das Bestehen der begleitenden Lehrveranstaltung der TU Wien sind, die ein wenig mehr Hintergrundinformationen liefern, unter Umständen um eine komplettere Beschreibung von Programmierinhalten zu liefern. Ganz nett zu lesen wenn du Zeit/Interesse hast, aber nicht wirklich wichtig.

Ganze Kapitel (oder Unterkapitel) die im Namen mit einem Stern (*) versehen sind, sind ähnlich zu verstehen wie kursiv gehaltene Absätze. Sie enthalten nützliche Weiterführende Kommentare, wo nicht gleich viel schiefgehen wird wenn man sie überliest, die aber dennoch sehr nützlich werden können.

Sehr wichtige Dinge werden hervorgehoben um sie zu betonen.

3

GRUNDLEGENDES

3.1 WIE ARBEITEN PROGRAMME? (INTERPRETER VS COMPILED)

Skriptsprachen (zB python) laufen „prozedural“, also einen Schritt nach dem anderen. Bei python bedeutet das, dass, wenn das Programm/Skript ausgeführt wird, Zeile für Zeile eingelesen wird, und die Befehle der Reihe nach abgearbeitet werden.

Es kann vorkommen dass dieses Prozedere von Schleifen unterbrochen wird (wo vom Schleifenende wieder an den Anfang gesprungen wird, dazu später mehr). Abgesehen davon „fängt es oben an“ und „hört unten auf“.

Kompilierte (compiled) Programme (z.B. in C, C++ geschrieben) funktionieren anders:

es gibt eine Unterscheidung in „Source-Code“ und „executable“ (menschenwürdig lesbarer Code und ausführbare Datei). Programmiert wird im Sourcecode, der dann Systemabhängig in eine executable „übersetzt“ werden muss (kompiliert – compiled), die anschließend ausgeführt werden kann. Probleme können hier sowohl beim Kompilieren als auch beim Ausführen auftreten. Die Ausführung kann in solch einem Fall unter Umständen schneller sein als bei Interpretern, wo im Prinzip jede Zeile einzeln während der „runtime“ übersetzt werden muss.

Wenn interaktive Programme geschrieben werden, die z.B. ein GUI (graphisches user interface) beinhalten, werden Dinge wie „event loops“ verwendet, sodass ein Fenster weiter angezeigt wird, auch wenn es gerade nichts gibt das der Prozessor tun könnte, und nur auf weitere Eingaben gewartet wird. Für solcherart Programmierung braucht es dann viele Dinge die wir noch kennenlernen werden.

Beginn:

gewartet wird. Für solcherart Programmierung braucht es dann viele Dinge die wir noch kennenlernen werden. Beginn:

5

Ende

3.2 EIN ERSTES PROGRAMM

Wir wissen jetzt im groben wie python arbeitet, also probieren wir das einmal.

Wir gehen Beispiel 1 Zeile für Zeile durch:

Zeilen 1, 4, 8, 14: Kommentare, siehe 3.4

Zeilen 2, 3, 7, 10, 13, 19: leere Zeilen

Diese Zeilen sind leer, und haben keine Auswirkung auf die Programmausführung, sie können gut für die Übersicht sein

Zeilen 5, 6, 9, 11, 12: Definitionen von Variablen

Hier definieren wir Variablen, die wir im späteren Verlauf verwenden können (z.B. die in Zeile 5, 6 definierten „a“ und „b“ können in einer Summe zur Definition von „c“ in Zeile 9 verwendet werden.

Zeilen 15-18: Ausgabe in der Konsole

Hier „drucken“ wir verschiedene Dinge in unsere Kommandozeile/Interpreter, und können damit in Variablen gespeicherte Werte gut sichtbar ausgeben.

Mittels Klick auf den „Run“ Button können wir unsere Befehle ausführen lassen, und die Ausgaben in der Konsole betrachten:

lassen, und die Ausgaben in der Konsole betrachten: 6 Beispiel 1 1. """Hier haben wir einen
lassen, und die Ausgaben in der Konsole betrachten: 6 Beispiel 1 1. """Hier haben wir einen

6

Beispiel 1

1.

"""Hier haben wir einen Kommentar"""

2.

3.

4.

# definieren von variablen

5.

a

= 2

6.

b

= 3

7.

8.

9.

10.

# simpler Befehl zum addieren von Variablen

11.

c

= a

+

b

12.

13.

d

= 5

14.

e

= c

+

d

15.

16.

# Ausgabe unserer Werte

17.

print c

 

18.

print "c= ", c

19.

print "unsere Werte a, b, c, d, e:"

20.

print a, b, c, d, e

3.3 VORSICHT! EINS NACH DEM ANDEREN…

Schauen wir uns das Beispiel 1 wieder an, nur definieren wir diesmal die Variable b bewusst erst nach der Zeile c = a + b.

Wie wir bereits wissen, beginnt python immer von oben und arbeitet sich von Zeile zu Zeile nach unten. Da in diesem Fall die Variable a erst nach der Rechenoperation c = a + bdefiniert wurde, bricht python schon in der Zeile 7 ab und es wird eine Fehlermeldung geworfen.

Es ist immer auf die Reihenfolge der Befehle zu achten!

Anmerkung: Sollte das Programm trotz falscher Anordnung funktionieren, entleere den Variable explorer oben rechts mit markieren und remove.

den Variable explorer oben rechts mit markieren und remove. Oft wird übersehen, dass python bereits Werte

Oft wird übersehen, dass python bereits Werte schon gespeichert hat und diese im ungünstigen Fall auch einsetzt. Spätestens wenn du das Programm neustartest, oder jemand dein Programm übernimmt, wirst du/er überrascht sein, warum dein Programm auf einmal nicht mehr funktioniert.

7

warum dein Programm auf einmal nicht mehr funktioniert. 7 Ausgabe mit Fehler: Hier kennt python „b“

Ausgabe mit Fehler:

dein Programm auf einmal nicht mehr funktioniert. 7 Ausgabe mit Fehler: Hier kennt python „b“ einfach
dein Programm auf einmal nicht mehr funktioniert. 7 Ausgabe mit Fehler: Hier kennt python „b“ einfach

Hier kennt python „b“ einfach noch nicht.

3.4 KOMMENTIEREN KOMMENTIEREN KOMMENTIEREN….

Sehr sehr wichtig beim Programmieren, egal in welcher Sprache, ist Übersichtlichkeit/Lesbarkeit, und damit Kommentare. Während an einem Projekt gearbeitet wird, sind viele Dinge klar und einfach, die dem Gedächtnis verloren gehen wenn man sich nur ein paar Tage/Wochen/Monate damit nicht mehr beschäftigt.

Sehr ausdruckstark und simpel zu beschreiben was ein bestimmter Code-Abschnitt macht (oder machen sollte) ist sehr hilfreich wenn sich andere den eigenen Code ansehen sollen/wollen, und dazu zähle ich auch den jeweiligen Code-Autor, nachdem ein paar Tage genügen um jeden soweit zu verändern dass der eigene Code schwer entzifferbar wi

In python ist alles was hinter einem „#“ in einer Zeile steht ein Kommentar, und beeinflusst die Programmausführung in keiner Weise. Längere Kommentare (über mehrere Zeilen) können mit dreifachen “ oder ‘ begonnen und beendet werden. Wichtig ist hier zu beachten, dass diese nicht vermischt werden dürfen.

3.5 * VERBOTENE NAMEN *

In python gibt es verschiedene Zeichenfolgen, die eine vordefinierte Bedeutung und Funktion haben, die in keiner anderen Weise verwendet werden SOLLTEN. Dabei muss zwischen „statements“ und „built-in functions“ unterschieden werden:

Wenn versucht wird statements als Variablennamen zu verwenden, wird eine Fehlermeldung ausgeworfen es ist sofort klar wo es hakt. Wenn eine vordefinierte Funktion (zu Funktionen später mehr) „überschrieben“ wird, ist das nicht sofort erkenntlich, die Funktion hat aber ihre Funktion verloren!

In Beispiel 2 (nächste Seite) wird die built-in Funktion „len()“ verwendet, die die Länge einer Variablen (so sie eine definierte Länge hat) zurückgibt. Sollten wir eine Variable „len“ nennen, können wir danach diese Funktion nicht mehr nutzen!

8

hat) zurückgibt. Sollten wir eine Variable „len“ nennen, können wir danach diese Funktion nicht mehr nu
hat) zurückgibt. Sollten wir eine Variable „len“ nennen, können wir danach diese Funktion nicht mehr nu

4

DATENTYPEN

4.1 VERSCHIEDENE DATENTYPEN IM ÜBERBLICK

Daten werden im Computer auf verschiedene Arten gespeichert, um korrekte Operationen damit durchführen zu können. Damit der Prozessor weiß, dass er zwei Objekte/Zahlen addieren kann, und wie diese Operation passiert, muss er zuerst wissen was diese Objekte eigentlich sind, und muss das korrekt gespeichert sein.

Dafür gibt es die verschiedenen Datentypen. Die einfachste ist ein „Integer“ (int), eine ganze Zahl, die (in python automatisch) auch negativ sein kann, jedoch per Definition kein Nachkommastellen haben kann. Im Vergleich dazu gibt es die „Floating point number“ (float), ein fast beliebig große (/kleine) Zahl, mit der Möglichkeit für viele Nachkommastellen.

Wie viele Zahlen/Nachkommastellen/höhe der Zahlen gespeichert werden können hängt davon ab wieviel Speicherplatz für diese eine Zahl zur Verfügung steht.

Wertebereich Integer bei 4 Bytes: -2147483648 bis 2147483647 (2.147x10 9 ) Wertebereich Gleitkomma bei 4 Bytes: 3.4x10 -38 bis 3.4x10 38 (Genauigkeit 7-8 Stellen)

Neben diesen Zahlentypen gibt es einen Datentyp für Text, den „String“ (str). Er

‘ , sowie

dreifachen “ oder ‘ . Wichtig dabei: Diese dürfen nicht vermischt werden!

kann in python auf unterschiedliche Art definiert werden: mit “

oder

Bestimmte Datentypen können miteinander “reden“ (man kann einen int mit einem float addieren), andere nicht ( str + int = Fehlermeldung).

Python erkennt automatisch den Datentyp, er muss nicht angegeben werden. Es ist jedoch wichtig darauf zu achten, WIE python das macht (was als was erkannt wird), um Fehler zu vermeiden.

9

Beispiel 2:

1.

a

= 5

# <int>

-- Integer

2.

b = 2. - Float(ing point number)

# <float> -

3.

c = 2.5

# <float>

4.

d = "hallo"

# <str>

-- String

5.

d = '12345'

# <str>

6.

e = "das ist 'cool'!"

# <str> (mit special)

7.

f = [1, 2, b, d, "hehe"] # <list> -- Liste

8.

g = {"drei": 3}

# <dict> -- Dictionary

9.

h = dict(drei=3)

# <dict>

10.

11.

12.

print "type of a

= ", type(a)

 

13.

print "type of b

= ", type(b)

 

14.

print "type of c

= ", type(c)

 

15.

print "type of d

= ", type(d)

 

16.

print "length of d = ", len(d)

 

17.

print "type of d

= ", type(d)

 

18.

print "length of d = ", len(d)

 

19.

print "type of e

= ", type(e)

 

20.

print "length of e = ", len(e)

 

21.

print "type of f

= ", type(f)

 

22.

print "length of f = ", len(f)

 

23.

print "type of g

= ", type(g)

 

24.

print "length of g = ", len(g)

 

25.

print "type of h

= ", type(h)

 

26.

print "length of h = ", len(h)

 

4.2

KOLLEKTIONEN

Kollektionen sind eine Zusammenstellung von mehreren Elementen. Diese können geordnet sein (Sequenzen wie Listen, Strings) oder ungeordnet (z.B. Sets und Dictionaries).

Die am häufigsten verwendeten Kollektionen sind Strings, Listen (Tupel) und Dictionaries. Einzelne Elemente von Kollektionen können mit Indizes oder Schlüsselwörtern („keywords“) abgerufen werden:

Wir verwenden aus Beispiel 2 die Variablen e, f & g:

Wir verwenden aus Beispiel 2 die Variablen e, f & g: Das Abrufen passiert mit eckigen

Das Abrufen passiert mit eckigen Klammern „[x]“.

Die Elemente von bestimmten Kollektionen (Lists, tuples, dicts) können jedwedes Objekt von python sein, einschließlich dieser Kollektionsarten, wobei unterschiedliche Typen wild miteinander vermischt werden können (in f sehen wir bereits eine Vermischung von ints, floats, und strings).

Wichtig zu beachten ist die Zählweise in den eckigen Klammern bei Indizes:

python beginnt bei „0“ (null) zu zählen, nicht bei „1“, das erste Element des Strings „e“ ist daher das „nullte“!

10

bei „0“ (null) zu zählen, nicht bei „1“, da s erste Element des Strings „e“ ist

4.3 STRING

Strings sind ganz einfach Textelemente, worin alle möglichen Zeichen gespeichert werden können. Sie sind nicht mit einem Zugriff über eckige Klammern veränderbar (stringwert[0] = ‘neuerstringwert am Anfang‘ Fehlermeldung!).

Sie können jedoch miteinander verbunden werden (+), und über viele verschiedene direkte Befehle manipuliert werden (siehe Dokument „Wichtige Befehle“).

4.4 LISTE

In einer Liste können quasi beliebig viele Elemente nacheinander angeordnet werden. Einzelne Listenelemente können abgegriffen und auch direkt verändert werden (eckige Klammern).

Eine Liste hat immer eine definierte Länge. Listenelemente mit Indizes außerhalb dieser Länge können nicht einfach mittels eckiger Klammern hinzugefügt werden! (verwende „.append()“ oder „.extend()“)

11

1.

a = '12345'

2.

b = "das ist 'cool'!"

3.

c = """das ist aber praktisch

4.

denn hier

5.

wird alles

6.

genau so

7.

wie es geschrieben wird

8.

auch gespeichert

9.

"""

10.

11.

print a

12.

print b

13.

print c

1.

a = range(4)

2.

print 'a = ', a

3.

print a[3], a[2], a[1]

4.

a.append(range(4))

5.

print 'a nach hinzufügen von element: '

6.

print a

7.

a.extend(range(4))

8.

print 'a nach erweiterung durch liste: '

9.

print a

10.

print '4. Element von a: ', a[3]

11.

a[3] = 'das sollte ALLES aendern

'

12.

print 'a nach direkter Änderung: '

13.

print a

14.

a[9] = 'ein Test'

' 12. print 'a nach direkter Änderung: ' 13. print a 14. a[9] = 'ein Test'
' 12. print 'a nach direkter Änderung: ' 13. print a 14. a[9] = 'ein Test'

4.5 DICTIONARY

Dictionaries sind Ansammlungen von Wertepaaren: Ein Schlüssel – „Key“ und ein Wert – „Value“ bilden in Paar. Die Values können mithilfe der Keys abgerufen werden.

Ein dict kann jederzeit nahezu beliebig verändert werden. Neue Wertepaare können eingefügt werden, als würden sie schon bestehen und nur verändert werden (eckige Klammern)!

Dies ist ein äußerst mächtiges Werkzeug von python, mit dem viele komplizierte Dinge im Code sehr einfach ausgedrückt werden können. Sobald es nicht nur um Zahlen, Vektor- und Array-artige Dinge geht (die dann sowieso besser mit spezielleren Werkzeugen behandelt werden) ist ein Dictionary die Methode der Wahl um Objekte gut auffindbar zu speichern, um sie während der Programmausführung zu verwenden!

4.6 AUFPASSEN BEI KOLLEKTIONEN!

Die Variablennamen in Kollektionen sind in python (für den Prozessor) im Prinzip nur Hinweise darauf WO die dahinterliegenden Werte gespeichert werden (im Prinzip wie Zeiger in C/C++). Wenn mehrere Namen für ein und dasselbe Objekt vergeben werden (Beispiel rechts, Zeile 3), dann weisen sie auch alle auf den gleichen Ort wird der Wert hinter einem der Namen geändert, ändert er sich auch hinter allen anderen Namen! (probiere nebenstehendes Beispiel aus!)

Um ein neues Objekt zu erzeugen muss eine „echte“ Kopie erstellt werden, bei Listen ist das einfach mittels „explizitem Kopieren“ möglich (Zeile 7).

Achtung: Bei Listen in Listen wird das komplizierter, und funktioniert nicht mehr mit explizitem Kopieren von der „höchsten“ Liste (in der alle anderen drinnen sind)!

Im Zweifelsfall stellt man an den Anfang des Skriptes ein from copy import deepcopyund definiert die kopierte Variable mit kopie = deepcopy(original)“. So kann nichts mehr schiefgehen!

12

1. meineAutos = dict(bmw=4, mercedes=2, Renault=1, Tesla=5)

2. print meineAutos

3. print 'Ich kaufe mir einen weiteren Tesla!'

4. meineAutos['Tesla'] = meineAutos['Tesla'] + 1

5. print meineAutos

6. print 'Ich kaufe mir jetzt noch einen Smart!'

7. meineAutos['smart'] = 1

8. print meineAutos

9. print 'wieviele versch. Automarken habe ich noch einmal? '

10. print len(meineAutos)

11. print 'und wieviele Autos sind das?'

12. print sum([x for x in meineAutos.values()])

(die letzte Zeile ist hier nur eine kleine Illustration wie einfach gewisse Dinge in python aussehen können, wenn man einmal den Dreh heraußen hat)

1. a = range(4)

2. print 'a = ', a

3. b

= a

4. b[0] = 5

5. print 'b = ', b

6. print 'a = ', a

7. c = a[:]

8. c[1] = 10

9. print 'a = ', a

10. print 'c = ', c

5 FALLUNTERSCHEIDUNGEN IF

Fallunterscheidungen kommen in Programmen sehr oft vor es wird etwas überprüft, und abhängig vom Ergebnis eine Aktion, oder eben eine andere Aktion gesetzt. In python funktioniert das wie rechts zu sehen ist.

Wichtig ist hierbei, dass in python die Einrückungen tatsächlich zur Syntax gehören! (siehe nächstes Kapitel)

„elif“ wird nur aufgerufen falls die darübergeordneten „elif“ oder „if“ NICHT zutreffen. Falls irgendetwas davon schon zutrifft wird diese Bedingung nicht überprüft! („elif“ ist wie wenn „else: if Condition:“ verwendet wird, wobei das neue if in einer neuen, eingerückten Zeile sein muss, und einen neuen Block beginnt)

Das Bedeutet, dass in dem rechtsstehenden Beispiel nie die Zeile „a ist kleiner als 0!“ angezeigt werden wird denn:

Wenn a größer als 3 ist, gibt es NUR die erste Meldung – alles was mit „el…“

das

anfängt,

dazupassende „if“ bereits zutrifft!

egal

ob

„else“

oder

„elif“

wird

nicht

beachtet

wenn

Wenn a kleiner als 3 ist gibt es daher NUR die zweite Meldung

Wenn a gleich 3 ist wird ausschließlich die 4. Meldung ausgegeben

Die letzte Meldung sollte nie ausgegeben werden!

Im zweiten Code-Beispiel rechts ist eine deutliche simplere Variante zu sehen. Im Prinzip muss neben dem „if“ immer etwas stehen das python als „wahr“ („True“) oder „falsch“ („False“) ermitteln kann.

Verschiedene Objekte die nicht von vornherein Wahrheitswerte SIND (Datentyp „bool“) werden unterschiedlich „bewertet“:

Ein leerer String (‘‘) ist immer False, sobald irgendwas enthalten ist True

Eine Liste verhält sich gleich (leer = False, nicht leer = True)

Ein Dictionary genauso (leer = False, nicht leer = True)

Ein Tupel ebenfalls (leer = False, nicht leer = True)

Der Integer null „0ist False, alle anderen Werte sind True

Das gleiche gilt für einen float

13

1.

a

= 5

2.

3.

if a > 3:

 

4.

print 'a ist größer als 3!'

5.

elif a < 3:

 

6.

pri nt 'a ist kleiner als 3!'

7.

elif a < 0:

 

8.

print 'a ist kleiner als 0!'

9.

elif a == 3:

 

10.

print 'a ist gleich 3!'

11.

else :

 

12.

print 'a ist seltsam

'

1.

if Condition:

2.

print 'It is true!'

6 * PYTHON SYNTAX: „CONTEXT“ („CONTEXT MANAGER”) *

6.1 * DATEIOPERATIONEN MIT DEM CONTEXT MANAGER *

In python können Leerzeichen stark zum Programm beitragen. Es gibt verschiedene Befehle, die voraussetzen, dass die darauffolgenden Zeilen eingerückt werden, und so mehr oder weniger als „Teil“ des Befehls deklariert sind. Das haben wir oben bei dem „if“ kennengelernt, und wird uns bei Schleifen und dem Öffnen von Dateien wieder begegnen.

Viele Dinge die damit zusammenhängen zu einem bestimmten Zeitpunkt eine Variable „verfügbar“ zu machen, damit kurz damit gearbeitet werden kann, und sie danach wieder „freigegeben“ wird, können so deutlich sicherer und einfach verständlicher gelöst werden!

Das „with“ statement sollte möglichst überall verwendet werden wo es verwendet werden kann es erleichtert das Leben ungemein….

7

SCHLEIFEN

In Schleifen wird der „normale“ Ablauf des Programmes unterbrochen, und ein gewisser Teil immer wieder wiederholt. Wie oft der Teil wiederholt wird kann unterschiedlich sein und hängt von unterschiedlichen Dingen (festgelegte Variablen usw, siehe unten) ab.

Wenn es irgendwelche Daten gibt, die in einer Sequenz vorliegen (listen, strings, tupel, dicts) kann in aller Regel „durch sie hindurch iteriert“ werden, und eine Schleife bietet sich an.

14

1.

with open('./eineDatei.txt', 'r') as datei:

2.

print datei.read()

3.

#man kann hier dann noch viel mehr anstellen

4.

5.

# im Vergleich dazu:

6.

datei = open('./eineDatei.txt', 'r')

7.

print datei.read()

8.

# falls zwischen open und close etwas crasht ist das schlecht

9.

datei.close()

7.1 DIE „FOR“ SCHLEIFE

Die for-Schleife in python ist im Prinzip eine „for each“ Schleife. Die Syntax lautet wie folgt:

1. for element in iterable:

2. # do something

3. print element

„iterable“ ist dabei ein Objekt in python, dass „iterierbar“ ist, also aus mehreren einzelnen Elementen besteht, die man eines nach dem anderen aufrufen kann. Dieses Objekt muss vor der Schleife bereits definiert und für python „vorhanden“ sein!

Im Grunde, ganz vereinfacht gesagt, alle Objekte bei denen man mit eckigen Klammern ein einzelnes Element „herauspicken“ kann (z.B. a = string[5]), sind jedenfalls iterierbar.

„element“ ist ein Variablenname, dessen Inhalt sich bei jedem Schleifendurchgang ändert. Illustriert an einer Liste ergibt sich folgendes:

1.

>>> Liste = ['a', 'b', 'c', 'd', 'e', 'f']

2.

>>> for element in Liste:

3.

print element

4.

5.

a

6.

b

7.

c

8.

d

9.

e

10.

f

11.

>>>

Bei jedem Schleifendurchgang wird ein Element aus der Liste „genommen“ und in „element“ verpackt, nachdem unsere Liste eine Ordnung hat (es gibt genau definierte Indizes, bei einem Dictionary ist das nicht so!) passiert das auch in genau dieser definierten Ordnung.

15

In „element“ steckt also bei jedem Schleifendurchgang ein neues Objekt, jeweils das Objekt bei dem wir innerhalb unserer Iteration durch die Sequenz gerade sind.

ACHTUNG: Wenn Elemente von Kollektionen verändert werden sollen, dürfen sie nicht einfach umdefiniert werden, sondern müssen wirklich als Element der Kollektion verändert werden!:

1. liste = list('0123456')

2. print liste

3. for element in liste:

4. element = int(element) + 1

5. print element

6. print liste

int(element) + 1 5. print element 6. print liste 1. liste = list( '0123456' ) 2.

1. liste = list('0123456')

2. print liste

3. for index in range(len(liste)):

4. liste[index] = int(liste[index]) + 1

5. print liste[index]

6. print liste

in range(len(liste)): 4. liste[index] = int(liste[index]) + 1 5. print liste[index] 6. print liste

7.2 DIE „WHILE“ SCHLEIFE

Bei einer while-Schleife wird nicht durch ein Objekt iteriert, sondern eine Bedingung abgefragt. Im Prinzip ist eine while-Schleife nichts anderes als eine „if“ Bedingung mit Wiederholung:

Wenn python zum ersten Mal an das Statement „ while Condition:” gelangt, wird der Wahrheitsgehalt von „Condition“ ermittelt. Falls das „True“ ist, wird alles was im Schleifenkörper definiert ist einmal ausgeführt (Im Fall von „False“ wird der Schleifenkörper direkt übersprungen). Am Ende dieser Ausführung wird der Wahrheitswert von „Condition“ erneut ermittelt, und falls er noch immer „True“ ist, wird die Schleife ebenfalls erneut ausgeführt. Das geht so lange, bis diese Bedingung nicht mehr als „True“ ausgewertet wird, ein Fehler auftritt (katastrophaler Programmabsturz), oder ein spezieller Befehl zur Unterbrechung der Schleifenausführung erreicht wird (siehe dazu das nächste Unterkapitel).

7.3 NÜTZLICHE SPEZIELLE SCHLEIFENOPERATOREN

Um gegebenenfalls eine Schleifendurchführung abbrechen zu können gibt es verschiedene Befehle. Am wichtigsten davon sind „break“ und „continue“.

„break“ bewirkt dass alles weitere was in dem Schleifenblock steht ignoriert wird, python an das Ende von diesem Block springt, und dort weiterarbeitet, wie als wenn gerade z.B. bei einer while-Schleife die Bedingung als „False“ ausgewertet wurde, oder die Iteration bei einer for-Schleife zu Ende ist.

„continue“ bricht die aktuelle Schleifendurchführung ab (genauso wie „break“), jedoch springt python danach nicht an das Ende des Blockes und arbeitet darunter weiter, sondern geht wieder an den Beginn der Schleife, und überprüft ob noch weitere Schleifenausführungen gemacht werden sollten (bei while wird wieder die Bedingung überprüft, bei for das nächste Element in der Iteration gesucht).

16

1. while Condition:

2. # do something!

3. print 'I am working!'

7.4

* PRAKTISCHE HINWEISE ZU SCHLEIFEN *

So es für eine bestimmte vordefinierte Funktion gibt, die es ermöglicht ein vorhandenes Problem zu lösen OHNE durch z.B. eine ganze Liste zu iterieren, dann ist diese in aller Regel zu bevorzugen, da sie sicher schneller läuft. Ein gutes Beispiel ist hier liste.remove(bestimmtes_element), was viel schneller ist als selbst jedes Element zu überprüfen und gegebenenfalls aus der Liste zu entfernen!

Um in einer for-Schleife nicht nur das jeweilige Element sondern auch den entsprechenden Index zu erhalten, gibt es eine nützliche built-in Funktion von python:

„enumerate“. Dabei wird unser iterierbares Objekt „nummeriert“, und immer sowohl das der jeweilige Index als auch das jeweilige Element zurückgegeben:

1.

>>> Liste = ['a', 'b', 'c', 'd', 'e', 'f']

2.

>>> for index, element in enumerate(Liste):

3.

print index, element

4.

5.

0 a

6.

1 b

7.

2 c

8.

3 d

9.

4 e

10.

5 f

11.

>>>

Dadurch können Konstruktionen wie die folgende vermieden werden:

1.

>>> for index in range(0, len(Liste)):

2.

element = Liste[index]

3.

print index, element

4.

5.

0 a

6.

1 b

7.

2 c

8.

3 d

9.

4 e

10.

5 f

11.

>>>

8

FUNKTIONEN

Funktionen sind im Prinzip Abkürzungen im Code. Eine spezielle Abfolge von Befehlen für den Computer wird in einem Objekt, „zusammengefasst“. Dieses Objekt hat definierte Eingänge (die Argumente/Parameter) und Ausgänge („return“ statements).

Variablen außerhalb einer Funktion werden von Manipulationen an Variablen im Funkionskörper („innerhalb“) im ersten Moment nicht beeinflusst. Wenn jedoch anstelle von Werten, Referenzen zu Variablen an eine Funktion übergeben werden, kann die Funktion (abgesehen vom Rückgabewert, „return“) sehr wohl Variablen außerhalb beeinflussen/ändern. Darauf sollte vor allem beim Übergeben von Sequenzen (Listen, Dictionaries usw) geachtet werden, da solche Manipulationen hier die Regel sind.

Wenn eine veränderliche Kollektion (Liste, Dictionary) übergeben wird, wird eigentlich nur eine Referenz zu dem Objekt übergeben, wodurch das Objekt selbst (d.h. auch außerhalb des Funktionsaufrufes) geändert wird, so es innerhalb des Funktionsaufrufes geändert wird.

Parameter können auf verschiedene Art und Weise übergeben werden: Bezüglich ihrer Position in der Funktionsdefinition, oder als Schlüsselwort. Es können auch mehrere Parameter auf einmal übergeben werden: Wenn sie als Schlüsselwörter übergeben werden mittels eines Dictionarys und zwei ‘*‘, bei einer Übergabe bezüglich der Position mittels einer liste und einem ‘*‘:

1.

a_dict = dict(st = 5, ab = 6)

2.

a_list = [5,6]

3.

def fun(st, ab):

4.

add = st + ab

5.

return add

6.

7.

print fun(**a_dict)

8.

print fun(*a_list)

18

1. def Funktionsbeispiel(parameter1, parameter2):

2. addition = parameter1 + parameter2

3. return addition

1. a = '23467gh'

2. def fun(st):

3. st += '3456ofg'

4. return st

5. print a

6. print fun(a)

7. print a

st 5. print a 6. print fun(a) 7. print a 1. a = list( '23467gh' )

1. a = list('23467gh')

2. print 'a= ', a

3. def fun(st):

4. st += '3456ofg'

5. return st

6. print 'in funktion:', fun(a)

7. print 'a= ', a

funktion:' , fun(a) 7. print 'a= ' , a Wenn in der Funktionsdefinition ein Parameter gleich

Wenn in der Funktionsdefinition ein Parameter gleich zugewiesen wird, erhält man einen optionalen Parameter:

1. def fun(st, ab = 8):

2. return st + ab

3. print fun(2)

Diese Zuweisung ist NIE eine Referenz, es wird dabei das Objekt zu dem Zeitpunkt „ausgelesen“ an dem die Funktion definiert wird, nicht bei jedem Funktionsaufruf!

9 LESEN UND SCHREIBEN VON DATEIEN

Wenn von Dateien gelesen werden, oder in Dateien geschrieben werden soll, muss immer ein entsprechendes „Fileobjekt“ geöffnet werden – und sollte im Anschluss das Fileobjekt auch wieder geschlossen werden.

(Erstens kann sonst kein anderes Programm sinnvoll auf die Datei zugreifen, und zweitens kann jedes Programm nur eine limitierte Anzahl von „File handles“, also geöffnete Dateien, gleichzeitig haben so man nie Dateien wieder schließt kann ein Skript irgendwann keine Dateien mehr öffnen. Das gilt für eine einzelne Ausführung eines Skriptes!)

Beim öffnen eines Fileobjektes muss sowohl der Dateiname (als string, kann auch als variable übergeben werden) angegeben werden als auch die Art wie die Datei behandelt werden soll. Es gibt:

r

w

a

r+

Lesen (read)

Schreiben (write)

Anhängen

Lesen &

(append)

schreiben

Wenn lesen ausgewählt wird, kann nur gelesen werden, wenn schreiben ausgewählt wird kann nur geschrieben werden dabei wird immer eine komplett neue Datei erstellt, eine Datei gleichen Namens wird überschrieben.

Wenn „append“ ausgewählt wird, wird nach einer Datei diesen Namens gesucht so solch eine Datei gefunden wird, werden alle Operationen an dem Fileobjekt an dieser bereits vorhandenen Datei durchgeführt, wenn keine solche Datei gefunden wird, wird eine neue erstellt. Der „Cursor“ in der Datei ist beim Öffnen der Datei ganz am Dateiende, sodass bei unmittelbaren Schreibaufrufen wirklich angehängt wird.

Wird ‘r+‘ ausgewählt, kann sowohl gelesen als auch geschrieben werden. Der „cursor“ in der Datei, ist beim Öffnen der Datei bei dem ersten Zeichen der Datei wenn sofort geschrieben wird, wird die Datei Zeichen für Zeichen überschrieben. So Leseoperationen durchgeführt werden, die die Cursorposition ändern, wird bei neuerlichem Schreiben dort weitergeschrieben!

19

Grundsätzliche Syntax um ein Fileobjekt zu bekommen:

1. fileobjekt = open(Dateiname, mode)

Einfaches Lesebeispiel:

1. fobj = open('meineDatei.txt', 'r')

2. for line in fobj:

3. print line

4. fobj.close()

Einfaches Schreibbeispiel:

1.

text = ['Das ist die erste Zeile', 'hier haben wir die zweite Zeile']

2.

3.

fobj = open('meineDatei.txt', 'w')

4.

for line in text:

5.

fobj.write(line + '\n')

6.

fobj.close()

Siehe * Python Syntax: „context“ („context manager”) * für eine allgemein nützliche Variante der Behandlung von Dateien.

10 AUSNAHMEBEHANDLUNG (EXCEPTION HANDLING)

Während der Ausführung eines Befehles / eines Skriptes, kann es zu Fehlern kommen (z.B. wenn versucht wird eine Datei zu öffnen die es nicht gibt). So diese Fehler (Ausnahmen) nicht behandelt/abgefangen (catching an exception) werden, stürzt das Programm/Skript einfach ab. Wenn zu vermuten ist, dass ein bestimmter Fehler auftreten könnte, kann man ihn abfangen, und eine eigene Reaktion darauf bestimmen (die z.B. sein könnte eine eigene Fehlermeldung auszugeben), wobei das Programm dann ungestört weiterlaufen kann.

Sobald eine Exception auftritt die Behandelt wird, springt die Programmausführung in den jeweiligen behandelnden Block, und alles weitere was im „try“ Block noch dabei steht wird ignoriert, und nicht mehr ausgeführt!

10.1 BEHANDLUNG VON MEHREREN FEHLERN

Es können mit einem „try-except“ Block mehrere Fehler auf einmal abgefangen werden, und das auf zwei unterschiedliche Arten:

Einerseits können Fehler unabhängig voneinander, mit unterschiedlicher Behandlung abgefangen werden, wie rechts oben zu sehen.

Andererseits können in einem einzelnen „except“ Statement mehrere Fehler gleichzeitig abgefangen werden:

1. try:

2. f = open('meineDatei.txt')

3. s = f.readline()

4. i = int(s.strip())

5. except (IOError, ValueError):

6. print 'Irgendwas ist hier schief gegangen'

20

Exception Beipsiel für den Umgang mit Dateien:

1. try:

2. f = open('meineDatei.txt')

3. s = f.readline()

4. i = int(s.strip())

5. except IOError as err:

6. print "I/O Fehler({0}): {1}".format(err.errno, err.strerr

or)

7. except ValueError:

8. print "Fehler: Der Dateiinhalt konnte nicht in einen Inte ger umgewandelt werden!"

Liste von den gängigsten Fehlern:

Exeption

Beschreibung

ImportError

import Statement findet das angegeben Modul nicht

IndexError

Tritt auf wenn ein Index bei einer Sequenz nicht existiert

IOError

Entsteht wenn eine Ein- Ausgabe Operation misslingt (Zugriff auf Datei).

KeyError

Tritt auf wenn ein Key bei einem Dictionary nicht existiert

NameError

Tritt auf wenn Name im Namensraum nicht existiert. (z.B. wenn eine Variable verwendet wird die noch nicht definiert wurde)

SyntaxError

Tritt bei Syntaxfehlern auf.

TypeError

Entsteht wenn ein Operator auf ein Objekt ungeeigneten Typs angewendet wird.

ZeroDivisionError

Tritt bei Divisionen durch null auf.

10.2 „ELSE“ UND „FINALLY“

An

dazugehörige Befehle angehängt werden: „else“ und „finally“.

einen

„try-except“

Block

wie

oben

beschrieben

können

noch

weitere

Alles was im „else“

Exceptions die abgefangen werden könnten, tatsächlich aufgetreten sind und abgefangen wurden, also „falls alles gut gegangen ist“.

Block steht, wird nur dann ausgeführt, wenn keine der

Was in einem „finally“ Block steht wird in JEDEM Fall ausgeführt, nachdem alles Vorherige durchgeführt wurde, ganz egal was dabei passiert sein könnte. Dies wird vor allem wichtig, wenn mehrere Funktionen sich untereinander, ineinander geschachtelt gegenseitig ausführen, und ein bestimmter Fehler (der eine Funktionsausführung unterbricht) erst eine „Funktionsstufe“ weiter oben behandelt wird – der Rest der Funktion wird in diesem Fall ignoriert!

10.3 „RAISE“

Sollte eine Programmierer*in irgendwann in die Versuchung kommen selbst eine Exception „werfen“ (throw) zu wollen, gibt es dafür das „raise“ Statement. Hierbei können die systemeigenen Exceptions (etwas wie „ValueError“), gerade aufgetretene Exceptions und eigene Exceptions (siehe „Zusätzliches“) geworfen werden.

10.4

*ZUSÄTZLICHES*

Es sollte immer genau angegeben werden welche Fehler abgefangen werden sollen! Es können zwar „alle“ Fehler mit einem Befehl abgefangen werden, dies macht jedoch die Fehlersuche beim Programmieren sehr schwierig, da Fehler mit denen man nicht rechnet unter Umständen komplett „stumm“ geschalten, und daher leicht übersehen

werden!

Eigene Exceptions müssen separat und vorab definiert werden. Dazu erstellt man eine

Klasse die von der Klasse „Exception“ erbt, die aber sonst nichts beinhalten muss. Und

damit

objektorientierte

Programmierung.

kommen

wir

zum

nächsten

Kapitel:

Klassen

und

21

1. try:

2. f = open('meineDatei.txt')

3. s = f.readline()

4. i = int(s.strip())

5. except (IOError, ValueError):

6. print 'Irgendwas ist hier schief gegangen'

7. else :

8. f.close()

9. finally :

10. print 'Endlich fertig mit den Dateien

'

1. try:

2. f = open('meineDatei.txt')

3. s = f.readline()

4. i = int(s.strip())

5. except (IOError, ValueError):

6. print 'Irgendwas ist hier schief gegangen'

7. except:

8. print 'Hier ist ordentlich was schief gegangen!'

9. raise

1. class meineException(Exception):

2. pass

11 OBJEKTORIENTIERTE PROGRAMMIERUNG

Ganz

Programmierung: imperativ (z.B. prozedural) und objektorientiert.

allgemein

gibt

es

zwei

Überbegriffe

für

unterschiedliche

Arten

von

Bei einem imperativen Programm liegt der Fokus auf den Funktionen die verwendet werden, und liegt das Programm meist als ein geschlossener Algorithmus vor, der als Ganzes, ein einziges Mal abgespult wird (prozedural).

Im Fall von objektorientierter Programmierung liegt der Fokus auf sogenannten „Klassen“ mit denen beliebige „Objekte“ anhand ihrer Eigenschaften beschrieben werden. Für diese Objekte können dann spezifische Funktionen („Methoden“) geschrieben werden, die Zugriff auf die jeweiligen Eigenschaften der Objekte haben (sie abrufen/verändern können).

Der Name „Klasse“ ist hier recht konkret zu sehen, da eine „Klasse“ immer eine ganze Klasse von Objekten beschreibt, und eine Abstraktion ist es kann beliebig viele einzelne Objekte dieser Klasse geben, die individuell manipuliert werden können, aber sich die gleiche Grundstruktur an Eigenschaften teilen.

(Autos haben immer eine Eigenschaft „Länge“, aber nicht alle Autos sind gleich lang – gleichzeitig kann ein einzelnes Auto unabhängig von den anderen plötzlich etwas kürzer werden….)

Beim Design einer Anwendung mit objektorientierter Programmierung kann die Struktur der einzelnen Klassen, wie sie zusammenhängen, was für Methoden sie haben (usw) vorab entworfen werden, ganz unabhängig von der Programmiersprache in der das Programm am Ende implementiert wird. Dafür verwendet man eine „UML“ (unified modeling language), bei der alles graphisch aufbereitet wird.

22

Objektorientierte Programmierung hat Vor- und Nachteile:

Vorteile:

Deutlich leichter lesbarer Code, sobald das behandelte Problem komplex wird

Modularität: Einzelne Teile können sehr unabhängig voneinander entwickelt, gewartet (Fehler finden) und erweitert werden

Wiederverwendbarkeit von Code Duplikationen werden vermieden, da für einzelne Objekte einer Klasse nicht alles neu definiert werden muss

Nachteile:

Höherer Aufwand zu Beginn, beim Design und der Implementierung, „es dauert länger bis ein Programm dann was kann“, erfordert mehr Schreibarbeit

o

Objektorientiertes Programmieren wird üblicherweise dann eingesetzt, wenn der anfänglich höhere Planungs- und Schreibaufwand später um ein Vielfaches durch leichtere Lesbarkeit und Wartbarkeit wiedergewonnen wird!

o

Bei der Behandlung eines Problems sollte man einfach etwas nachdenken was am sinnvollsten ist, bevor man mit einer Variante „drauf los“ programmiert!

Unter Umständen längere Laufzeiten dies ist jedoch oft eine intrinsische Eigenschaft der Probleme die mit objektorientiert geschriebenen Programmen behandelt werden (hohe Komplexität), und allgemein abhängig von der Implementierung

Objektorientierte Programmierung baut auf 4 Bestandteilen auf:

Datenkapselung

Vererbung

Polymorphismus

Abstraktion

11.1

KLASSEN

Eine Klasse besteht in aller Regel aus (der Häufigkeit nach angeordnet, Beschreibungen weiter unten):

1. Der Klassenbezeichnung, also dem eigenen Namen

2. „Eltern“ – „parent“ (wenn es auch nur „object“ ist), siehe Vererbung

3. Dynamische Attribute

a. Variablen die an die jeweilige Instanz gebunden sind

b. Funktionen/Methoden

4. Einen „Konstruktor“, und/oder andere python-spezifische „lower-level“

Funktionen (mit „magic

Kontext von python selbst ändern.

“)

die das Verhalten von Klassenobjekten im

5. Einen Docstring

6. Statische Attribute

Zu 1.: jedes Objekt braucht in python einen Namen, also auch eine Klasse….

Für 2., die Vererbung brauchen wir erstmal etwas das wir vererben können, und das wären zum Beispiel dynamische Attribute, 3.:

11.1.1 DYNAMISCHE ATTRIBUTE

Klassen haben wie Funktionen ihren eigenen Namensraum, das bedeutet, dass Objekte (z.B. Variablen) die in ihrem Inneren erstellt werden, nicht notwendigerweise auch außerhalb der Klasse aufrufbar sind. Bevor dynamische Attribute einer Klasse abgerufen werden können, muss sie „instanziert“ werden, es muss also ein Objekt dieser Klasse erzeugt werden, von dem Attribute gelesen und modifiziert werden können. Die dynamischen Attribute einer Klasse können dann wieder beliebige Objekte sein, alles von einfachen Integern oder Listen, bis hin zu aufrufbaren („callable“) Funktionen oder sogar anderen Klassen oder Instanzen von anderen Klassen.

vorab

festgelegt werden, sie können aber nachträglich beinahe beliebig verändert werden

(daher „dynamisch“).

Diese

dynamischen

Attribute

können

gleich

in

der

Klassendefinition

23

1. class Beispielklasse(object):

2. """Hier sollte eine Beschreibung dieser Klasse stehen"""

3. einstatisschesAttribut = 5

4. def

init (self,

bspparam **kwargs):

5. self.beispielvariable = 1

6. self.beispielparameter = bspparam

7. def druckvars():

 

8. print self.beispielvariable, self.beispielparameter

Dynamische Attribute von Klassen sind immer an die jeweilige Instanz gebunden:

wird ein solches Attribut von einer Instanz geändert, ändert es sich bei keiner anderen Instanz!

Dadurch kann man zum Beispiel die Klasse „Auto“ mit einer Eigenschaft „Farbe“ ausstatten, und dann mehrere Instanzen erstellen, die verschiedene Autos beschreiben, die verschieden lackiert sind.

Methoden einer Klasse sind wie Funktionen, wobei das erste Argument bei der Definition „self“ ist, wodurch die „aktuelle“ Instanz übergeben wird. Dies muss/darf bei Verwendung der Methode nicht mehr extra gemacht werden! (siehe dazu unten noch mehr)

11.1.2 METHODEN

Methoden von Klassen kommen in vielen Dingen normalen Funktionen gleich. Es gelten die gleichen Regeln bezüglich der Argumente die übergeben werden, genauso wie das Verhalten bezüglich „call by value“ vs „call by reference“.

Ein wichtiger Unterschied ist jedoch „self“: Das erste Argument in der Methodendefinition ist immer „self“ (bis auf bei „classmethods“ aber das würde hier zu weit führen). „self“ repräsentiert die jeweilige Instanz, wodurch innerhalb der Methode auf alle Attribute (dynamische wie statische) zugegriffen werden kann. Beim Aufruf einer Methode (egal ob innerhalb der Klassendefinition oder außerhalb) muss und sollte selbige Instanz dann nicht noch einmal übergeben werden, und das „erste Argument“ „entfällt“, wird einfach ignoriert.

11.1.3 KONSTRUKTOR UND „MAGIC“

Gleich bei der Erstellung eines Objektes einer Klasse können Attribute/Variablen dynamisch vergeben werden, dies passiert im sogenannten „Konstruktor“:

In python können tieferliegende Vorgänge in der Programmiersprache durch Veränderung von „magischen“ Funktionen beeinflusst werden. Diese sind durch

am Beginn und Ende des Funktionsnamens gekennzeichnet. Variablen und

eigene Funktionen sollten allgemein NICHT so benannt werden, nur „hauseigene“

Funktionen sollten umdefiniert werden.

Eine wichtige solche Funktion ist der Konstruktor einer Klasse. Ein Beispiel dafür ist rechts oben zu sehen. Hier werden zwei Attribute festgelegt, eines das zu Beginn immer 5 ist, und ein anderes, dass beim Instanzieren der Klasse definiert werden muss. Rechts unten ist ein Beispiel zu sehen, bei dem derselbe Konstruktor in einer Klasse („Beispiel“) zusammen mit einer Methode gezeigt ist.

Es gibt eine Vielzahl weiterer „magische“ Befehle, die mit „

wir werden mehrere später unter „Polymorphismus“ kennenlernen.

beginnen und enden,

24

1.

def

init (self,

attr2):

2.

self.attribut1 = 5

3.

self.attribut2 = attr2

1.

class Beispiel(object):

 

2.

3.

def

init (self,

attr2):

4.

self.attribut1 = 5

5.

self.attribut2 = attr2

6.

7.

def bspmethode_add(self, new)

8.

return self.attribut2 + new

9.

10.

Beispiel_eins = Beispiel(1) # erste instanzierung

11.

Beispiel_zwei = Beispiel(2) # zweite instanzierung

12.

13.

# aufrufen der Methode an der jeweiligen Instanz

14.

print Beispiel_eins.bspmethode_add(4)

15.

print Beispiel_zwei.bspmethode_add(4)

11.1.4 DOCSTRINGS

Um eine einfach zu verwendende Dokumentation zu erlauben, können Klassen, Funktionen und Methoden mit einem „docstring“ ausgestattet werden, siehe

rechts. Ein Docstring kann mittels „

den Quellcode eines Moduls ansehen zu müssen. Bei Code der mit anderen gemeinsam verwendet wird, sollte jede Klasse, Funktion und Methode einen Docstring besitzen, wie selbsterklärend der Code auch sein mag.

direkt abgerufen werden, ohne sich

doc

11.1.5 STATISCHE ATTRIBUTE

Variablen die direkt nach dem Beginn der Klassendefinition und dem docstring zugewiesen werden, vor jeder Methode, inklusive dem Konstruktor, werden zu statischen Klassenattributen. Statisch bedeutet in diesem Fall, dass wenn sich ein solches Attribut ändert, es sich in allen einzelnen Instanzen (und dem Klassenobjekt selbst) gleichzeitig ändert!

ACHTUNG: Eine solche Änderung kann nur an der Klasse selbst, nicht jedoch an den einzelnen Instanzen vorgenommen werden. Wenn das versucht wird, wird das statische Attribut mit einem dynamischen überschrieben, und verliert seine Eigenschaft.

25

1.

def BspFunktion(par1):

 

2.

'''Das hier ist der docstring'''

3.

return par1 * 2

4.

5.

print BspFunktion

doc

1.

class Beispielklasse(object):

2.

'''Hier sollte eine Beschreibung dieser Klasse stehen'''

3.

4.

statAttribut = 2

5.

6.

def

init (self,

attr2):

7.

self.attribut1 = 5

 

8.

self.attribut2 = attr2

9.

11.2

VERERBUNG

11.2.1 GRUNDLAGEN

Ein wichtiger Vorteil der erwähnt wurde ist die Wiederverwendbarkeit von Code. Dies wird erreicht durch Instanzierung und Vererbung. Instanzierung kennen wir schon, es können von einer Klasse beliebig viele Objekte erzeugt werden. Vererbung geht weit darüber hinaus:

Bei OOP geht es im Allgemeinen darum Objekte über ihre Eigenschaften zu beschreiben. Dabei wird allgemeines von speziellerem zu trennen. Nehmen wir als Beispiel Handys:

Die grundlegenden Eigenschaften aller Handys sind gleich: man kann mit ihnen telefonieren. Einige Eigenschaften haben nur „bestimmte Klassen von Handys“, nur mit Smartphones kann man das Internet erreichen (fast). Jedes iPhone läuft mit einer Version von iOS, jedes Android-Handy mit…Android. Sobald klar ist dass auf einem Handy Android läuft, ist vieles andere klar, Eigenschaften sind festgelegt es gibt aber noch immer sehr viele verschiedene Android Handys. Um nicht bei jedem Android Handy hinschreiben zu müssen „es kann telefonieren“, erbt es diese Eigenschaft von der Klasse der „Smartphones“. Die Smartphones jedoch erben diese Eigenschaft letztendlich von der allgemeinsten Klasse „Handy“.

Das Beispiel rechts enthält ausschließlich statische Attribute die Vererbung nimmt jedoch auch alles andere (Methoden, dynamische Attribute usw.) mit.

auch alles andere (Methoden, dynamische Attribute usw.) mit. 26 1. class Handy(object): 2. kanntelefonieren =

26

1.

class Handy(object):

2.

kanntelefonieren = True

3.

hateineAntenne = True

4.

hatLautsprecher = True

5.

6.

class Smartphone(Handy):

7.

internetfaehig = True

8.

touchscreen = True

9.

10.

class Android_phone(Smartphone):

11.

OS = 'Android'

12.

rootzugriff = 'simpel'

13.

googletracking = True

14.

15.

class iPhone(Smartphone):

16.

OS = 'iOS'

17.

rootzugriff = 'schwierig'

18.

googletracking = True

19.

appletracking = True

20.

applesymbol = True

21.

Hersteller = 'Apple'

22.

23.

class SamsungGalaxyS9(Android_phone):

24.

Hersteller = 'Samsung'

25.

RAM = '4GB'

26.

Speicher = '64GB'

27.

Navigation = ['GPS', 'GLONASS', 'BeiDou', 'Galileo']

28.

29.

class iPhoneX(iPhone):

30.

RAM = '3GB'

31.

Speicher = '64GB'

32.

Navigation = ['GPS', 'GLONASS', 'Galileo']

33.

34.

meiniPhoneX = iPhoneX()

35.

meiniPhoneX.hateinenSprung = True

36.

print 'kann telefonieren: ', meiniPhoneX.kanntelefonieren

37.

print 'hat einen Sprung: ', meiniPhoneX.hateinenSprung

11.2.2 AUSFÜHRUNG IN PYTHON

In python schreibt man, wenn man eine Klasse von einer anderen erben lassen will,

die

einer

Funktionsdefinition, siehe rechts.

Klasse

von

der

man

erben

will

ähnlich

wie

ein

Argument

in

New style classes: wenn die oberste, ältesteKlasse, die ganz oben steht in der Generationenreihenfolge von objecterbt (wie rechts implementiert), dann kann man zusätzliche praktische Features verwenden. Ich empfehle IMMER diese Version einer Klasse zu verwenden. Es gibt keinen Grund (außer extremer Schreibfaulheit, die schon viele Editoren und IDEs abnehmen) es nicht zu tun!

11.2.3 FEINHEITEN

Wenn Methoden in einer child-Klasse definiert werden, die in einer parent-Klasse von der sie erbt schon vorhanden sind, werden diese Methoden einfach überschrieben. Das ist in vielen Fällen erwünscht, manchmal jedoch nicht, ein wichtiges Beispiel ist hier der Konstruktor einer Klasse.

Im Regelfall wollen wir die Funktionalität des Konstruktors einer parent-Klasse erhalten, da ohne sie die Klasse nicht funktioniert. Dafür kann man die parent- Klasse und deren Methoden direkt aufrufen, siehe rechts.

Anstatt die parent-Klasse so direkt noch einmal anzuschreiben kann man auch die Funktion super()verwenden. Da diese Funktion in der LVA an der TU nicht verwendet wird lasse ich sie hier aus, wen es interessiert, denen kann ich diesen Talk empfehlen:

27

1.

def Funktion(argument):

 

2.

# irgendwas

 

3.

pass

4.

5.

class parentClass(object):

 

6.

# nix

7.

pass

8.

9.

class childClass(parentClass):

 

10.

# oder doch was?

 

11.

pass

1.

class Konto:

 

2.

""" Basis Konto Klasse """

 

3.

4.

def

init (self,

inhaber, kontonummer, kontostand):

5.

""" Konstruktor, Aufruf bei Instanzierung """

6.

print "

Konto anlegen"

 

7.

self.Inhaber = inhaber

 

8.

self.Kontonummer = kontonummer

9.

self.Kontostand = kontostand

10.

self.zeige_konto()

 

11.

12.

13.

class Girokonto(Konto):

 

14.

""" Giro Konto Klasse """

 

15.

16.

def

init (self,

inhaber, kontonummer, kontostand, soll

 

zinsen, habenzinsen):

 

17.

""" Giro Konstruktor, Aufruf bei Instanzierung """

18.

self

Sollzinsen

= sollzinsen

19.

self

Habenzinsen

= habenzinsen

20.

# initialisiere Konto

 

21.

Konto

init

(self,

inhaber, kontonummer, kontostand

 

)

11.3

PRIVATE ATTRIBUTE UND DATENKAPSELUNG

11.3.1

GRUNDSÄTZLICHES

Eine weithin als wichtig angesehene Eigenschaft der Objektorientierten Programmierung ist die Datenkapselung, die Eigenschaft, dass bestimmte Attribute „private members“ einer Klasse sind, und von außerhalb der Klasse nicht abgerufen werden können.

Einerseits werden dadurch die inneren Vorgänge der Klasse „geschützt“, sodass kein unautorisierter Zugriff stattfinden kann, andererseits werden dadurch Variablennamen frei, die man anders belegen kann was jedoch noch immer tunlichst vermieden werden sollte (es ist nicht immer vom Code einfach ersichtlich was für ein Objekt worauf genau Zugriff hat).

11.3.2 AUSFÜHRUNG IN PYTHON

In python sind Klassenattribute die mit zwei Unterstrichen beginnen („ und können (eigentlich) nur von innerhalb der Klasse abgerufen werden.

“)

privat,

Dies betrifft jede Art von Attribut, egal ob statisch, dynamisch, Variable oder Methode. Ausgenommen sind python-eigene „magische“ Operatoren/Methoden, “

die zwar mit „

beginnen, aber auch so enden.

28

1.

class Bsp(object):

 

2.

fingerweg

= True

3.

fingerweg = False

 

4.

5.

A = Bsp()

6.

print 'public fingerweg: ', A.fingerweg

7.

print 'private fingerweg: ', A

fingerweg

11.3.3 „SET“ UND „GET“ METHODEN

Um dann doch Zugriff auf private Attribute einer Klasse zuzulassen werden i.A. „setter“ und „getter“ verwendet: zwei Methoden, mithilfe derer man ein privates Attribut modifizieren (set) oder abrufen (get) kann. Innerhalb dieser Methoden können dann z.B. Restriktionen eingebaut werden, wo überprüft werden kann ob die abfragende Stelle überhaupt die Berechtigung für einen Zugriff hat.

Gleichzeitig kann man damit, wenn es entsprechend definiert wird, es aussehen lassen als wäre die Variable tatsächlich eigentlich öffentlich („public“), da setter und getter den gleichen Namen tragen.

Viel nützlicher als bei der Implementation von Restriktionen und Zugriffsbeschränkungen, können setter und getter bei der Kommunikation mit Hardware sein: So ein Gerät in einer Klasse „abstrahiert“ ist, können Einstellungen des Gerätes modifiziert und abgerufen werden als wäre es tatsächlich nur ein Klassenattribut, da im Hintergrund bei set und get jeweils unterschiedliche Aktionen ausgeführt werden. Dies funktioniert besonders gut mit der Funktion property:

11.3.3.1

Mit der Funktion propertykann man setter und getter verbinden (letzte Zeile Codebeispiel oben rechts), sodass man es verwenden kann wie ein dynamisches, öffentliches Attribut (von der Syntax her). Es gibt jedoch noch viel Raum für Hintergrundaktivität beim modifizieren oder abrufen des Klassenattributes.

PROPERTY

Wenn man es noch etwas spannender machen möchte, kann man auch @propertyverwenden, siehe rechts.

29

1.

class Bsp(object):

 

2.

3.

def

init

(self):

4.

self

private

= 'this is private'

5.

6.

def setattr(self, priv):

7.

self

private

= priv

8.

9.

def getattr(self):

 

10.

return self

private

11.

12.

Attribut = property(getattr, setattr)

1.

class Bsp(object):

 

2.

3.

def

init

(self):

4.

self

private

= 'this is private'

5.

6.

@property

 

7.

def Attribut(self):

 

8.

return self

private

9.

10.

@Attribut.setter

 

11.

def setattr(self, priv):

12.

self

private

= priv

11.3.4 * „PROGRAMMING GUIDELINES“ FÜR PYTHON KRITISCHE BETRACHTUNG *

Python als Programmiersprache wurde bestimmten Prinzipien folgend erdacht. Eines davon ist „We are all adults“ (ein anderes ist zB „there must be a better way!“).

Die Datenkapselung bringt auf dem Code-Level keine echte Sicherheit: Wenn ein Angreifer bereits so direkt auf Objekte Zugriff hat, hat er „schon gewonnen“. Es ist viel eher dafür gedacht, dass ein unbedarfter Programmierer, der nur von außen auf die Objekte zugreifen können soll, nicht irgendwo im Inneren herumpfuscht, da er sich nicht auskennt, aber einfach mal in seiner/ihrer Überheblichkeit annimmt er/sie wisse was sie tun.

Daher wird empfohlen, Variablen und Methoden die nicht von außen „angefasst“ werden sollten, mit einem einzelnen Unterstrich („_“) beginnen zu lassen (zB. „_passwort_entschlüsseln()“), um ganz klar zu zeigen, dass man von dieser Variable/Methode besser die Finger lassen sollte. Jedoch werden für Programmierer*innen die sich wirklich sicher sind dass sie wissen was sie tun, keine unnötigen Hürden gebaut, und wenn dann etwas schief geht ist man definitiv „selbst schuld“.

11.4

ABSTRAKTION

Datenkapselung und private Attribute sind eng verbunden mit dem Prinzip der Abstraktion:

Eine Klasse sollte ein Set an Methoden haben, die „public“ sind, und mithilfe derer mit einem Objekt der Klasse interagiert werden kann. Diese sollten sich möglichst im Verlauf der Entwicklung einer Anwendung nicht ändern, sodass alles „umliegende“ nicht geändert werden muss, wenn an der Implementation der Klasse selbst (z.B. ein Update für bessere Performance) etwas geändert wird. Damit wird die Implementation von der Interaktion mit dem Objekt getrennt.

30

1.

class Bsp(object):

2.

_fingerweg_besserso = True

3.

fingerweg = False

4.

5.

A = Bsp()

6.

print 'public fingerweg: ', A.fingerweg

7.

print 'quasi-private fingerweg: ', A fingerweg_besserso

11.5

POLYMORPHISMUS

12 SCHNITTSTELLEN ZUM BETRIEBSSYSTEM

32

Methode

Beschreibung

os.chdir(path)

Setzt das aktuelle Arbeitsverzeichnis auf den mit path übergebenen Pfad.

os.getcwd()

Gibt String zurück, welcher Pfad des Arbeitsverzeichnisses (Current Working Directory) enthält.

os.chmod(path,

Setzt die Zugriffsrechte der Datei oder des Ordners.

mode)

os.listdir(path)

Gibt Liste aller Dateien und Unterordner des “path” Ordners zurück.

os.mkdir(path)

Legt einen neuen Ordner in dem mit “path” übergebenen Pfad an.

os.makedirs(path)

Legt einen neuen Ordner sowie dazwischenliegende Ordner an sofern diese nicht existieren.

os.rmdir(path)

Entfernt den übergebenen Ordner aus dem Dateisystem sofern dieses leer ist.

os.removedirs(path)

Entfernt den mit “path” angegebenen Ordner inklusive darunterliegender Ordner sofern diese leer sind.

os.remove(path)

Entfernt die mit “path” angegebene Datei aus dem Dateisystem.

os.rename(src, dst)

Benennt die mit “src” angegebene Datei oder den Ordner in “dst” um.

shutil.copy(src,dst)

Kopiert Datei “src” nach “dst”.

shutil.move(src,dst)

Verschiebt Datei “src” nach “dst”.

13

TESTEN

14 DATENSPEICHERUNG

15 GRAPHISCHE BENUTZEROBERFLÄCHE

16 NETZWERKKOMMUNIKATION

17 SOFTWARE ENGINEERING - THEORIE