Python 3

Werbung
Arbeitsgruppe Programmiersprachen und Übersetzerkonstruktion
Institut für Informatik
Christian-Albrechts-Universität zu Kiel
Seminararbeit
Python 3
Ilonka Pingel
Bugenhagenstr. 4
24114 Kiel
[email protected]
Stand: 22.02.2013
Betreuer: Priv.-Doz. Dr. Frank Huch
Inhaltsverzeichnis
1 Einordnung
1.1 Geschichte und Entwicklung von Python
1.2 Unterstütze Programmierparadigmen . .
1.3 Anwendungsgebiet . . . . . . . . . . . .
1.3.1 Intention . . . . . . . . . . . . .
1.3.2 Einsatzbeispiele . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
2
2
2
2
2 Konzepte und Struktur
2.1 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.1 Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.2 Modularisierung . . . . . . . . . . . . . . . . . . . . . .
2.1.3 Typisierung . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.4 Referenzen und Kopien . . . . . . . . . . . . . . . . . .
2.1.5 Beliebige Anzahl Parameter und Standardwerte . . . . .
2.2 Funktionale Programmierung . . . . . . . . . . . . . . . . . . .
2.2.1 Anonyme Funktionen und Funktionen höherer Ordnung
2.3 Objektorientierte Programmierung . . . . . . . . . . . . . . . .
2.3.1 Klassen und Vererbung . . . . . . . . . . . . . . . . . .
2.3.2 Magic Methods und Magic Attributes . . . . . . . . . .
2.4 Exceptionhandling . . . . . . . . . . . . . . . . . . . . . . . . .
2.5 Automatisiertes Testen . . . . . . . . . . . . . . . . . . . . . . .
2.5.1 Modul doctest . . . . . . . . . . . . . . . . . . . . . . .
2.5.2 Modul unittest . . . . . . . . . . . . . . . . . . . . . .
2.6 Besonderheiten . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.6.1 Annotationen . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
3
4
4
4
6
7
7
8
8
12
12
13
14
15
17
17
3 Technische Unterstützung
3.1 Compiler, Interpreter und Entwicklungsumgebungen
3.2 Werkzeuge und Bibliotheken . . . . . . . . . . . . . .
3.2.1 Interaktive Umgebung . . . . . . . . . . . . .
3.2.2 Standardbibliothek . . . . . . . . . . . . . . .
3.3 Portabilität . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
19
19
19
19
20
20
4 Zusammenfassung und Fazit
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
21
ii
1 Einordnung
1.1 Geschichte und Entwicklung von Python
Die Programmiersprache Python wurde Anfang der 1990er Jahre von Guido van Rossum
(* 31. Januar 1956) am Centrum voor Wiskunde en Informatica (CWI, s. http://www.cwi
.nl) in Amsterdam entwickelt. Dieser hatte bereits bei der Entwicklung der Lehrsprache
ABC mitgewirkt, die als Vorgängersprache von Python gilt. Auch Einflüsse aus C sind
bei der Entwicklung von Python eingegangen. Dieser Einfluss findet sich unter Anderem
in der umfassenden Standardbibliothek wieder, da die Funktionen des Moduls math
den mathematischen Funktionen entsprechen, die vom C Standard definiert werden.
Gedacht war Python ursprünglich für das verteilte Betriebssystem Amoeba (s. http://
www.cs.vu.nl/pub/amoeba) und als Lehrsprache, da sie durch ihre besonders simple
Syntax sehr einfach zu erlernen sei. Der Name der Sprache geht zurück auf die englische
Komikergruppe Monty Python, wodurch sich in der Dokumentation immer wieder Anspielungen auf Sketche von Monty Python finden lassen (z.B. heißen die traditionellen
Variablen nicht foo oder bar, sondern spam oder eggs).
Die erste Version von Python wurde 1991 veröffentlicht. 1995 hat van Rossum die Entwicklung von Python bei der Corporation for National Research Initiatives (CNRI, s.
http://www.cnri.reston.va.us) in Reston, Virginia, fortgeführt, wechselte aber im Mai
2000 gemeinsam mit dem Python-Entwicklerteam zu BeOpen.com und gründete das
BeOpen PythonLabs Team. Noch im Oktober desselben Jahres wechselten sie zu Digital Creations (heute Zope Corporation; s. http://www.zope.com). 2001 wurde dann die
Python Software Foundation (PSF, s. http://www.python.org/psf) gegründet, welche bis
heute Bestand hat und unter deren Namen bis dato die meisten Softwareversionen von
Python veröffentlicht wurden (zuletzt 2012 Python 3.3.0). Alle Python-Versionen sind
Open Source und unterliegen der PSF-Lizenz (s. http://www.docs.python.org/3/license.
html). Hierbei ist zu erwähnen, dass sämtliche Python 3.x Versionen nicht mehr abwärtskompatibel zu früheren Versionen sind, es jedoch Methodiken gibt, älteren Python-Code
in Python-3-Code zu überführen.
Guido van Rossum ist bis heute, trotz der vielen Beiträge von anderen, hauptverantwortlicher Autor. In seinem Vorschlag "Computer Programming for Everybody" [1], den
er 1999 an die DARPA (Defense Advanced Research Projects Agency, s. http://www.
darpa.mil) sendete, hielt van Rossum seine Ziele für Python fest. So solle Python eine
einfache, intuitive, aber dennoch eine sehr mächtige Sprache sein, deren Quelltext genauso einfach zu lesen sein soll wie die englische Sprache. Außerdem müsse sie dennoch für
tägliche Aufgaben geeignet sein und kurze Entwicklungszeiten ermöglichen. Weiterhin
1
1 Einordnung
war ihm immer wichtig, dass Python Open Source Software ist. Diese Ziele sind bis heute
weitestgehend erreicht worden [1].
1.2 Unterstütze Programmierparadigmen
Python unterstützt gleich mehrere Programmierparadigmen, was stark zur großen Flexibilität der Sprache beiträgt. Sie ist in erster Linie eine imperative, dynamisch, streng
getypte Programmiersprache, die objektorientiertes Programmieren unterstützt. Auch
unterstützt Python einige funktionale Aspekte. Des Weiteren wird aspektoritiertes Programmieren ermöglicht und Python kann beziehungsweise wird häufig als Skriptsprache
benutzt.
1.3 Anwendungsgebiet
1.3.1 Intention
Aufgrund ihrer Flexibilität kann die Sprache Python sowohl für kleine als auch für große
Programme eingesetzt werden (s. 1.3.2). Sie lässt sich als serverseitige Programmieroder auch als Skriptsprache verwenden und auch in eingebetteten Systemen kann sie
problemlos eingesetzt werden. Es gibt beispielsweise viele Python-Interpreter für mobile
Endgeräte wie Smartphones, PDAs etc. [2, S.30].
Die automatische Speicherverwaltung und die umfangreiche Standardbibliothek erlauben
es, bereits mit kleinen Programmen komplexe Probleme zu beschreiben, daher wird
Python oft für das (Rapid-)Prototyping eingesetzt.
1.3.2 Einsatzbeispiele
Python wird in vielen unterschiedlichen Bereichen benutzt. So sind zum Beispiel WebAnwendungen wie GoogleMail (s. http://mail.google.com), YouTube (s. http://www
.youtube.com), Dropbox (s. http://www.dropbox.com) oder Programme im Bereich des
Filesharing (z.B. BitTorrent, s. http://www.bittorrent.com), aber auch Entwicklerwerkzeuge wie Mercurial (s. http://mercurial.selenic.com) oder Computerspiele (z.B. Civilization IV (s. http://www.2kgames.com/civ4/home.htm), Battlefield 2 (s. http://
www.battlefield.com/de/battlefield-2)) zumindest teilweise in Python implementiert.
Python wird von anderen Anwendungen zur Anbindung von Erweiterungen als Skriptsprache unterstützt. Eine solche Unterstützung bieten beispielsweise die Grafikprogramme
Blender (s. http://www.blender.org), Cinema 4D (s. http://www.maxon.net/de/products
/cinema-4d-studio.html) oder auch GIMP (s. http://www.gimp.org).
Ein weiteres Einsatzgebiet stellt die testgetriebene Entwicklung von Programmcode dar,
denn Pythons Standardbibliothek stellt das Modul unittest zur Verfügung, welches die
Funktionalitäten des aus Java bekannten Moduls JUnit implementiert.
2
2 Konzepte und Struktur
2.1 Grundlagen
2.1.1 Form
Einzelne Python-Programme beziehungsweise -Module sind simpel aufgebaut. Wenn
benötigt, werden zu Beginn des Codes Module oder Pakete mit der import-Anweisung
geladen. Auf Funktionen eines Moduls kann dann per modulname.funktion zugegriffen
werden. Dies sorgt dafür, dass sich gleichnamige Funktionen aus verschiedenen Modulen nicht gegenseitig behindern, denn so befinden sie sich jeweils in einem eigenen
Namensraum. Anschließend kann direkt mit dem eigentlichen Code begonnen werden.
Hierbei ist zu beachten, dass Python keinerlei Begrenzungszeichen wie Klammern oder
Semikolons, wie man sie aus Sprachen wie C oder Java kennt, benutzt. Es wird lediglich
über Zeilenumbrüche und Einrückungstiefen bestimmt, wo ein Ausdruck endet und zu
welchem Kopf ein Ausdruck beziehungsweise ein ganzer Rumpf gehört (vgl. Syntax von
Haskell). Das folgende Beispiel zeigt die funktional programmierte Fibonacci-Funktion.
Fibonacci
1
2
3
4
5
6
7
def f i b ( n ) :
i f ( n == 0 ) :
return 1
e l i f ( n == 1 ) :
return 1
else :
r e t u r n f i b ( n−1) + f i b ( n−2)
Code, der auf niedrigster Einrückungstiefe geschrieben wird und eine Anweisung ist, ist
Code, der direkt ausgeführt wird, sobald die zugehörige Datei beziehungsweise das Modul ausgeführt wird. Man kann diesen also vergleichen mit Code, der in C oder Java in
der main-Methode steht. Beim restlichen Code handelt es sich dann um Funktions- oder
Klassendeklarationen, die innerhalb oder außerhalb des Moduls, sofern dieses importiert
wird, benutzt werden können. Lokale Funktionen können definiert werden, indem sie
innerhalb des Rumpfes einer anderen Funktion definiert werden, also auf entsprechender Einrückungstiefe unterhalb des Funktionskopfes bezüglich dessen die Funktion lokal
sein soll. Kommentare werden als sogenannte Docstrings geschrieben. Hierfür wird der
eigentlich Kommentar durch dreifache " oder ’ eingefasst. Solche Docstrings lassen sich
zu Dokumentationszwecken bequem aus Python-Dateien auslesen. Zu beachten ist noch,
3
2 Konzepte und Struktur
dass return-Statements immer optional sind, was beispielsweise in C anders aussieht,
da dort konventionsgemäß beim problemlosen Ablauf der main-Methode immer die Zahl
Null zurückgegeben wird. Dateien beziehungsweise Module, wie im Beispiel zu sehen,
werden mit dem Namen modulname.py abgespeichert, in diesem Fall also form.py.
2.1.2 Modularisierung
Wie bereits erwähnt, handelt es sich bei den einzelnen Python-Dateien jeweils um Module, die zu Paketen zusammengefasst werden können. Dies bietet die Möglichkeit, große
Programme in mehrere Teile zu unterteilen, um so die Komplexität zu reduzieren, Übersichtlichkeit zu schaffen und den Abstraktionsgrad durch Kapselung von Programmcode
zu erhöhen. Man unterscheidet hierbei zwischen sogenannten globalen und lokalen Modulen. Globale Module sind Module, die Datentypen und Funktionen bereitstellen, die
einen thematisch abgegrenzten Zweck erfüllen. Dies sind also systemweit installierte
Module, welche sich auch selbst erstellen lassen oder von Drittanbietern zur Installation bereit gestellt werden. Beispiele hierfür sind die Module der Standardbibliothek wie
math oder random. Lokale Module hingegen dienen in erster Linie der Zerlegung eigenen Programmcodes in Teile mit unterschiedlichen Zuständigkeiten. Im Gegensatz zu
den globalen Modulen sind diese Module allerdings nicht systemweit verfügbar, sondern
müssen mit ihren absoluten oder relativen Pfaden eingebunden werden.
2.1.3 Typisierung
Bei Python handelt es sich um eine streng getypte Programmiersprache mit dynamischer
Typprüfung, wobei das sogenannte Duck-Typing verwendet wird. Das heißt erstens, dass
die Typen von Variablen und Funktionen im Programmcode erst zur Laufzeit feststehen
und zweitens, dass nicht die Klasse eines Objektes den Typ festlegt, sondern die Existenz
von bestimmten Methoden und Attributen. Der Name Duck-Typing findet dabei seinen
Ursprung in einem Gedicht von James Whitcomb Rileys.
When I see a bird that walks like a duck and swims like a duck and quacks
like a duck, I call that bird a duck. [3]
Typfehler treten also erst dann auf, wenn ein Operator auf Typen angewendet wird,
für die er nicht definiert ist. Tritt ein solcher Fehler aufgrund von fehlerhaften Benutzereingaben auf, kann es sinnvoll sein, diese Eingaben mithilfe einer selbstgeschriebenen Typprüfung zu kontrollieren. Eine solche Typprüfung kann mittels Typ-Annotationen (s. Abschnitt 2.6.1) und Exceptionhandling (s. Abschnitt 2.4) realisiert werden.
2.1.4 Referenzen und Kopien
In Python ist alles ein Objekt. Das heißt, auch die üblicherweise primitiven Datentypen
wie int oder float sind Objekte, ebenso wie Exceptions, Funktionen oder Module. Der
Typ ist aufgrund der dynamischen Typisierung an die Instanz selbst und nicht an die
referenzierende Variable gebunden. Beim Benutzen selbiger ist jedoch Vorsicht geboten,
4
2 Konzepte und Struktur
da hier unerwartete und vor allem ungewollte Nebenwirkungen durch Seiteneffekte bei
mutablen Datentypen entstehen können. Python arbeitet, wenn dies nicht explizit anders
angegeben wird, nur mit Referenzen auf Instanzen, was bei immutablen Datentypen
keinerlei Problem darstellt, jedoch bei mutablen Datentypen zu kritischen Situationen
führen kann, wie die folgenden Beispiele aus der interaktiven Python-Umgebung (s.
Abschnitt 3.2) zeigen.
Referenzen vs. Kopien - Beispiel 1
1
2
3
4
5
6
7
8
9
>>>
>>>
>>>
[1 ,
>>>
>>>
[1 ,
>>>
[1 ,
xs
ys
ys
2,
xs
xs
2,
ys
2,
= [1 ,2 ,3]
= xs
3]
+= [ 3 , 4 , 5 ]
3 , 3 , 4 , 5]
3 , 3 , 4 , 5]
Ein solches Verhalten kann insbesondere in sicherheitskritischen Bereichen zu unerwünschten Möglichkeiten führen. Wird mittels einer getter-Funktion die Referenz auf ein
Attribut einer Klasse zurückgegeben, die einen mutablen Datentypen referenziert, ist es
anschließend möglich, über diese Referenz auch das Klassenattribut zu verändern.
Um solche Probleme zu umgehen, sollte man also im entsprechenden Kontext mit Kopien
von Instanzen arbeiten. Dann würde das erste Beispiel von oben wie folgt aussehen.
Referenzen vs. Kopien - Beispiel 1 (Korrektur)
1
2
3
4
5
6
7
8
9
>>>
>>>
>>>
[1 ,
>>>
>>>
[1 ,
>>>
[1 ,
xs
ys
ys
2,
xs
xs
2,
ys
2,
= [1 ,2 ,3]
= xs [ : ]
3]
+= [ 3 , 4 , 5 ]
3 , 3 , 4 , 5]
3]
Hierbei ist die Verwendung von xs[:] (vgl. Slicing [2, S. 123]) gleichbedeutend mit
dem Ausdruck copy.copy(xs). Aber auch hier ist Vorsicht geboten. Beinhaltet nämlich der kopierte Datentyp wieder mutable Datentypen, so werden für diese erneut nur
Referenzen erzeugt. Um auch für diese echte Kopien zu erhalten, muss die Funktion
copy.deepcopy verwendet werden, welche rekursiv für alle beinhalteten Objekte Kopien
5
2 Konzepte und Struktur
erzeugt. Man sollte jedoch nicht nur noch Kopien von Instanzen erzeugen, denn dies
kann, gerade bei großen Datenmengen, zu einem sehr hohen Zeitaufwand und einem
unnötig hohen Speicherbedarf eines Programms führen. Außerdem lassen sich mithilfe
von copy.copy beziehungsweise copy.deepcopy nicht von allen Datentypen echte Kopien erzeugen. Module, Funktionen und wenige weitere Objekte werden durch Benutzung
dieser Funktionen lediglich ein weiteres Mal referenziert [2, S. 522].
2.1.5 Beliebige Anzahl Parameter und Standardwerte
Python ermöglicht es sehr simpel, einer Funktion eine beliebige Anzahl von Parametern
zu übergeben. Betrachte die Funktion, die das Produkt zweier Zahlen berechnet.
Produkt zweier Zahlen
1
2
def p r o d ( a , b ) :
r e t u r n a ∗b
3
4
5
6
’ ’ ’ B e i s p i e l e f u e r Benutzung von p r o d ’ ’ ’
p r i n t ( prod (2 , 4))
p r i n t ( prod (6 , prod (42 , prod (21 , 9 ) ) ) )
Wie in den Beispielen zur Benutzung der Funktion prod zu sehen ist, ist es so kein Problem das Produkt zweier Zahlen zu berechnen. Möchte man nun das Produkt mehrerer
Zahlen berechnen, so sehen die Aufrufe schnell sehr unschön aus und man muss für jeden
zusätzlichen Faktor einen neuen Aufruf von prod erzeugen. Folgende Code-Erweiterung
ist da schon deutlich besser.
Produkt von zwei oder mehr Zahlen
1
2
3
4
5
def p r o d ( a , b , ∗ o t h e r ) :
r e s u l t = a ∗b
for i in other :
r e s u l t ∗= i ;
return r e s u l t
6
7
8
9
’ ’ ’ B e i s p i e l e f u e r Benutzung von p r o d ’ ’ ’
p r i n t ( prod (2 , 4))
p r i n t ( prod (6 , 42 , 21 , 9))
Hier zeigt sich nun der Vorteil, dass nicht nur das Produkt von zwei, sondern auch das
Produkt einer beliebigen Anzahl Zahlen berechenbar ist und zwar einfach durch das
Hinzufügen weiterer Parameter. Der Parameter *other referenziert hier alle möglichen
weiteren Parameter in Form eines Tupels. Es werden von der Funktion aber immer
noch mindestens zwei Parameter gefordert. Mathematisch ist es möglich das leere oder
6
2 Konzepte und Struktur
einstellige Produkt zu berechnen, daher ergibt sich folgende optimierte und sehr elegante
Möglichkeit das Produkt beliebig vieler Zahlen zu berechnen.
Produkt mehrerer Zahlen
1
2
3
4
5
def p r o d ( ∗ a r g s ) :
result = 1
for i in args :
r e s u l t ∗= i ;
return r e s u l t
2.2 Funktionale Programmierung
In Python ist es bequem möglich auch funktionale Programme zu schreiben. Das Beispiel
aus Abschnitt 2.1.1 berechnet per Rekursion die n-te Fibonacci-Zahl.
2.2.1 Anonyme Funktionen und Funktionen höherer Ordnung
Python stellt das Schlüsselwort lambda zur Verfügung, mit dessen Hilfe anonyme Funktionen deklariert werden können. Solche Ausdrücke werden meist für kleine, häufig
benötigte Berechnungen benutzt. Das folgende Beispiel zeigt zwei Varianten die zweistellige prod-Funktion aus Abschnitt 2.1.5 mithilfe des lambda-Ausdrucks zu definieren.
Die zweite Variante zeigt lediglich, dass Variablen anonyme Funktionen referenzieren
können.
Prod als lambda-Ausdruck
1
2
3
4
5
>>> ( lambda a , b : a ∗b ) ( 4 , 4 )
16
>>> p r o d = lambda a , b : a ∗b
>>> p r o d ( 4 , 4 )
16
Solche anonymen Funktionen sind insbesondere bei der Verwendung von Funktionen
höherer Ordnung nützlich. Hier werden einer Funktion eine oder mehrere Funktionen als
Parameter übergeben. Dies ermöglicht es, sehr allgemeine und mächtige Funktionen zu
schreiben. Im Folgenden sieht man eine solche Funktion höherer Ordnung anhand des
Beispiels filter_list. Diese Funktion ist in der Lage aus beliebigen Listen diejenigen
Elemente herauszufiltern, für die ein frei wählbares Prädikat p wahr wird. Somit wird
die Wiederverwendbarkeit von filter_list erhöht, da es je nach Situation flexibel
anpassbar ist.
7
2 Konzepte und Struktur
filter_list
1
2
3
4
5
6
7
8
def f i l t e r _ l i s t ( p , l i s ) :
def f i l t e r _ h e l p ( n ) :
i f ( n >= l e n ( l i s ) ) :
return [ ]
e l i f (p( l i s [ n ] ) ) :
r e t u r n [ l i s [ n ] ] + f i l t e r _ h e l p ( n+1)
else :
r e t u r n f i l t e r _ h e l p ( n+1)
9
10
return f i l t e r _ h e l p (0)
Die folgenden Zeilen zeigen einige beispielhafte Verwendungsmöglichkeiten, wobei darauf
zu achten ist, dass sich lambda-Ausdrücke nur innerhalb einer Zeile definieren lassen.
Beispiele - filter_list
1
2
3
4
5
6
7
8
>>> f i l t e r l i s ( lambda n : n < 5 , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 2 0 , 2 1 , 4 2 , 1 0 0 ] )
[1 , 2 , 3 , 4]
>>> f i l t e r l i s ( lambda n : n % 2 == 0 ,
[1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,20 ,21 ,42 ,100])
[ 2 , 4 , 6 , 8 , 20 , 42 , 100]
>>> f i l t e r l i s ( lambda s t r : " i n " i n s t r ,
[ " I c h " , " b i n " , " e i n e " , " L i s t e " , " von " , " S t r i n g s " ] )
[ ’ bin ’ , ’ eine ’ , ’ Strings ’ ]
2.3 Objektorientierte Programmierung
2.3.1 Klassen und Vererbung
Um in Python eigene Objekte erzeugen zu können, müssen für diese Konstruktionsschablonen, sogenannte Klassen, definiert werden. Als Beispiel dient hier die Klasse Vehicle
mit den Attributen manufacturer, maxSpeed und currentSpeed sowie der Methode
accelerate implementiert. Der Konstruktor heißt hier, wie auch in jeder anderen Klasse,
__init__. Jede Methode, auch der Konstruktor, erwartet als erstes Argument die Referenz self auf sich selbst, wobei diese beim Verwenden der Methoden nicht explizit
übergeben werden muss. Attribute werden im Allgemeinen nur innerhalb des Konstruktors definiert. Es gibt auch andere Wege dies zu tun, von diesen wird allerdings abgeraten,
weshalb diese Möglichkeit hier nicht vorgestellt wird.
8
2 Konzepte und Struktur
Klasse - Vehicle
1
2
3
4
5
6
7
class Vehicle :
’ ’ ’ Konstruktor ’ ’ ’
def __init__ ( s e l f , m a n u f a c t u r e r , maxSpeed ) :
’ ’ ’ G e s c h w i n d i g k e i t e n i n m/ s ’ ’ ’
s e l f . manufacturer = manufacturer
s e l f . maxSpeed = maxSpeed
self . currentSpeed = 0
8
9
10
11
12
13
14
’ ’ ’ Methode zum B e s c h l e u n i g e n d e s V e h i k e l s , w o b e i a c c e l e r a t i o n
i n m/ s ^2 und d u r a t i o n i n s e r w a r t e t werden . ’ ’ ’
def a c c e l e r a t e ( s e l f , a c c e l e r a t i o n , d u r a t i o n ) :
newSpeed = s e l f . c u r r e n t S p e e d + d u r a t i o n ∗ a c c e l e r a t i o n
i f ( newSpeed <= s e l f . maxSpeed ) :
s e l f . c u r r e n t S p e e d = newSpeed
Verwendet werden kann eine solche Klasse dann folgendermaßen.
Verwendung der Klasse Vehicle
1
import v e h i c l e
2
3
4
5
v = v e h i c l e . V e h i c l e ( " Audi " , 1 4 )
v . a c c e l e r a t e (1 , 5)
p r i n t ( " neue G e s c h w i n d i g k e i t : " , v . c u r r e n t S p e e d , "m/ s " )
6
7
8
9
10
11
’’’
Ausgabe a u f d e r K o n s o l e b e i A u s f u e h r u n g d i e s e s Moduls :
l i l o @ l i l o −ACER: ~ $ p y t h o n v e h i c l e _ b s p . py
neue G e s c h w i n d i g k e i t : 5 m/ s
’’’
Wie oben zu sehen ist, kann man auf die Attribute der Klasse Vehicle nicht nur von
innerhalb der Klasse zugreifen, sondern auch von außen. Dies ist in vielen Fällen nicht
gewünscht, sodass man setter- und getter-Methoden für solche Attribute schreibt,
um kontrolliert auf sie zuzugreifen. In diesem Fall kann dann auch die Überprüfung
bezüglich der Überschreitung der Maximal-Geschwindigkeit durch den setter durchgeführt werden, was stilistisch schöner ist und somit die Logik der accelerate-Methode
sauber hält. Des Weiteren werden konventionsgemäß alle Attribute, auf die von außen
nur per getter- beziehungsweise setter-Methode zugegriffen werden soll, mit einem
Unterstrich beginnend geschrieben. Modifiziert man die Klasse Vehicle dahingehend,
ergibt sich nun folgendes Bild, wobei hier zur Übersicht nur die getter und setter von
currentSpeed ergänzt wurden.
9
2 Konzepte und Struktur
Klasse - Vehicle - Erweiterung
1
2
3
4
5
6
7
class Vehicle :
’ ’ ’ Konstruktor ’ ’ ’
def __init__ ( s e l f , m a n u f a c t u r e r , maxSpeed ) :
’ ’ ’ G e s c h w i n d i g k e i t e n i n m/ s ’ ’ ’
s e l f . _manufacturer = manufacturer
s e l f . _maxSpeed = maxSpeed
s e l f . _currentSpeed = 0
8
9
10
def g e t C u r r e n t S p e e d ( s e l f ) :
return s e l f . _currentSpeed
11
12
13
14
def s e t C u r r e n t S p e e d ( s e l f , newSpeed ) :
i f ( newSpeed <= s e l f . _maxSpeed ) :
s e l f . _ c u r r e n t S p e e d = newSpeed
15
16
17
18
19
20
’ ’ ’ Methode zum B e s c h l e u n i g e n d e s V e h i k e l s , w o b e i a c c e l e r a t i o n
i n m/ s ^2 und d u r a t i o n i n s e r w a r t e t werden . ’ ’ ’
def a c c e l e r a t e ( s e l f , a c c e l e r a t i o n , d u r a t i o n ) :
s e l f . setCurrentSpeed ( s e l f . getCurrentSpeed ()
+ duration ∗ acceleration )
Führt man nun allerdings den Beispiel-Code (s. Verwendung der Klasse Vehicle S.
9) aus (den direkten Zugriff hierbei um den nötigen _ ergänzt), stellt man fest, dass
der Code fehlerlos terminiert. Das heißt, dass _currentSpeed immer noch nicht vor der
Verwendung von außen geschützt ist. Es existiert lediglich eine Schnittstelle, über die das
Attribut verwendet werden sollte, daher auch die konventionsgemäße Schreibweise mit
_. Es gibt in Python keine Möglichkeit Attribute gegen Zugriffe von außen zu schützen.
Ersatzweise verwendet man die sogenannten Property-Attribute. Ist für ein Attribut
ein Property-Attribut deklariert, so wird bei jeder direkten Verwendung des PropertyAttributs implizit der getter- beziehungsweise setter-Methode gerufen. Um dies zu
demonstrieren, wird zunächst die Klasse Vehicle modifziert und anschließend erneut
der unveränderte Beispiel-Code ausgeführt. Wie im Folgenden zu sehen ist, werden nun
trotz der intuitiven und scheinbar direkten Verwendung des Attributs currentSpeed die
jeweiligen getter- und setter-Methoden verwendet.
10
2 Konzepte und Struktur
Klasse - Vehicle mit Property-Attribut
1
2
3
4
5
class Vehicle :
...
def g e t C u r r e n t S p e e d ( s e l f ) :
print ( " getCurrentSpeed gerufen " )
return s e l f . _currentSpeed
6
7
8
9
10
11
12
def s e t C u r r e n t S p e e d ( s e l f , newSpeed ) :
print ( " setCurrentSpeed gerufen " )
i f ( newSpeed <= s e l f . _maxSpeed ) :
s e l f . _ c u r r e n t S p e e d = newSpeed
...
currentSpeed = property ( getCurrentSpeed , setCurrentSpeed )
13
14
15
16
17
18
19
20
’’’
Ausgabe a u f d e r K o n s o l e :
getCurrentSpeed gerufen
setCurrentSpeed gerufen
getCurrentSpeed gerufen
neue G e s c h w i n d i g k e i t : 5 m/ s
’’’
Möchte man eine Klasse Car implementieren, ist es sinnvoll, sie von der Klasse Vehicle
erben zu lassen. Die Klasse Car sieht dann folgendermaßen aus, wobei irrelevante Teile
des Codes der Übersicht halber weggelassen wurden.
Klasse - Car
1
import v e h i c l e
2
3
4
5
6
7
8
9
10
11
12
c l a s s Car ( v e h i c l e . V e h i c l e ) :
def __init__ ( s e l f , m a n u f a c t u r e r , maxSpeed , f u e l S o r t ,
maxTankLevel ) :
v e h i c l e . V e h i c l e . __init__ ( s e l f , m a n u f a c t u r e r , maxSpeed )
self . _fuelSort = fuelSort
’ ’ ’ M a x i m a l e r T a n k f u e l l s t a n d und a k t u e l l e r F u e l l s t a n d i n
l. ’’’
s e l f . _maxTankLevel = maxTankLevel
s e l f . _currentTankLevel = 0
...
An dieser Stelle sei kurz angemerkt, dass in Python die Mehrfachvererbung zwar möglich,
aber recht kompliziert ist. Außerdem wird im Allgemeinen davon abgeraten sie zu benutzen. Daher wird an dieser Stelle auf diese nicht weiter eingegangen.
11
2 Konzepte und Struktur
2.3.2 Magic Methods und Magic Attributes
In Python gibt es einige sogenannte Magic Methods beziehungsweise Magic Attributes,
die Klassen besondere Fähigkeiten verleihen. Diese Methoden beginnen und enden jeweils mit __. Sie werden als "magisch" bezeichnet, weil sie üblicherweise nicht direkt mit
ihrem Namen, sondern implizit im Hintergrund aufgerufen werden. Es handelt sich um
einen festen Satz von Magic Methods beziehungsweise Magic Attributes. Die __init__Methode ist eine dieser Methoden. Sie wird implizit beim Verwenden eines Konstruktors ausgeführt. Solche Methoden können beispielsweise benutzt werden, um Operatorüberladungen zu ermöglichen, also das Verwenden desselben Operators auf Instanzen
verschiedener Datentypen. Hierzu muss eine Klasse bloß die zum Operator gehörige
Methode implementieren. Dies hat man auch schon anhand des Operators + gesehen,
denn man kann mit ihm nicht bloß Zahlen addieren, sondern auch Listen oder Strings
konkatenieren, weil die entsprechenden Klassen die Methode __add__(self, other)
implementieren. Ein Beispiel für ein Magic Attribute wird im Kontext der Annotations
(s. Abschnitt 2.6.1) gegeben.
2.4 Exceptionhandling
In Python wird das Konzept des Exceptionhandlings ähnlich umgesetzt wie in Java. Es
gibt eine gemeinsame Basisklasse, BaseException, von der alle eingebauten Exceptions
erben und von der auch alle selbst definierten Exceptions am Ende der Vererbungshierarchie erben sollten. Werfen kann man eine Exception mithilfe des Schlüsselwortes raise.
Betrachte hierfür nochmal die Beispielklasse Vehicle. Dort wird im setter des Attributes currentSpeed zunächst überprüft, ob die neue Geschwindigkeit nicht eventuell
dazu führt, dass das Vehikel die maximale Geschwindigkeit überschreitet. Ist das nicht
der Fall, so wird die neue Geschwindigkeit übernommen. Ist die Geschwindigkeit jedoch
zu hoch, so wird hier noch nichts unternommen. Dies wäre also eine geeignete Stelle, um
eine Exeption zu werfen. Um das Beispiel kurz zu halten, wird hier keine eigene Exception definiert, sondern die bereits implementierte Exception RuntimeError verwendet.
Exception werfen
1
2
3
4
5
6
7
8
9
class Vehicle :
...
def s e t C u r r e n t S p e e d ( s e l f , newSpeed ) :
i f ( newSpeed <= s e l f . _maxSpeed ) :
s e l f . _ c u r r e n t S p e e d = newSpeed
else :
e r r o r M s g = ( " Die neue G e s c h w i n d i g k e i t i s t zu hoch . " )
raise RuntimeError ( errorMsg )
...
12
2 Konzepte und Struktur
Anschließend muss man nun noch das Abfangen der Exception in unserem Testprogramm
von vorhin realisieren. Hierfür wird die try-except- beziehungsweise try-exceptelse-finally-Anweisung benutzt, sodass das Testprogramm wie folgt aussieht und
sich die angegeben Ausgabe ergibt.
Exception fangen
1
import v e h i c l e
2
3
4
5
6
7
8
9
10
11
12
v = v e h i c l e . V e h i c l e ( " Audi " , 1 4 )
try :
v . a c c e l e r a t e (5 , 5)
except R u n t i m e E r r o r a s e :
print ( " Fehlermeldung : " , e . args [ 0 ] )
else :
" w i r d a u s g e f u e h r t , wenn k e i n e E x c e p t i o n g e w o r f e n w i r d "
finally :
" w i r d immer a l s l e t z t e s a u s g e f u e h r t , u n a b h a e n g i g davon , ob \
e i n e E x c e p t i o n g e w o r f e n wurde o d e r n i c h t "
13
14
15
16
17
’’’
Ausgabe a u f d e r K o n s o l e b e i A u s f u e h r u n g d i e s e s Moduls :
F e h l e r m e l d u n g : Die neue G e s c h w i n d i g k e i t i s t zu hoch .
’’’
Wie erwartet, wird nun beim Ausführen des obigen Testprogramms die RuntimeErrorException vom setter geworfen und vom Testprogramm abgefangen. Dem Benutzer
wird somit mitgeteilt, dass das Vehikel nicht so schnell fahren kann. Neben dem tryBereich, in dem der Code steht, dessen Ausführung zum Auftreten einer Exception
führen kann, und dem except-Bereich, in dem der Code zur Fehlerbehandlung steht,
sind noch zwei weitere Punkte aufgeführt. Diese sind beide optional und bieten die im
Code beschriebenen Möglichkeiten.
2.5 Automatisiertes Testen
Python wird häufig für das Test-Driven Devolpment (deut. testgetriebene Entwicklung,
auch TDD) benutzt. Hierfür stellt die Standardbibliothek zwei Module zur Verfügung.
Diese sind doctest und unittest. Mithilfe von doctest können innerhalb von Docstrings Testfälle definiert werden, während unittest die Funktionalitäten des JavaModuls JUnit implementiert [2, S. 718].
13
2 Konzepte und Struktur
2.5.1 Modul doctest
Man betrachte das Beispiel zum Berechnen der Fibonacci-Zahlen vom Anfang und
ergänze den Code nun um einen Docstring mit Testfällen.
Fibonacci - doctest
1
import d o c t e s t
2
3
4
def f i b ( n ) :
’ ’ ’ B e r e c h n e t d i e n−t e F i b o n a c c i Z a h l .
5
6
7
8
9
10
11
>>> f i b ( 4 )
5
>>> f i b ( 1 5 )
987
>>> f i b ( 2 5 )
121393
12
13
Es muss e i n e Z a h l >= 0 u e b e r g e b e n werden .
14
15
16
17
18
19
>>> f i b ( −2)
T r a c e b a c k ( most r e c e n t c a l l l a s t ) :
...
ValueError : Keine n e g a t i v e n Zahlen .
’’’
20
21
22
23
24
25
26
i f ( n == 0 ) :
return 1
e l i f ( n == 1 ) :
return 1
else :
r e t u r n f i b ( n−1) + f i b ( n−2)
27
28
29
i f (__name__ == "__main__" ) :
d o c t e s t . testmod ( )
Die einzelnen Testfälle haben die Form, die sie beim direkten Aufrufen der Funktion in
der interaktiven Umgebung hätten. Für Testfälle, die Fehler erzeugen, muss nicht der
gesamte Stacktrace notiert werden, es reichen stattdessen auch "..." aus. Hier werden
die Testfälle mit doctest.testmod() aufgrund der if-Bedingung nur dann ausgeführt,
wenn dieses Modul direkt ausgeführt wird, also nicht, wenn das Modul per import von
anderen Modulen eingebunden wird. Führt man das Modul aus, erhält man folgende
Meldung.
14
2 Konzepte und Struktur
Fibonacci - doctest-Testergebnisse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
’’’
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
F i l e " f i b _ d o c t e s t . py " , l i n e 1 5 , i n __main__ . f i b
F a i l e d example :
f i b ( −2)
Expected :
T r a c e b a c k ( most r e c e n t c a l l l a s t ) :
...
ValueError : Keine n e g a t i v e n Zahlen .
Got :
T r a c e b a c k ( most r e c e n t c a l l l a s t ) :
...
R u n t i m e E r r o r : maximum r e c u r s i o n d e p t h e x c e e d e d i n c o m p a r i s o n
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
1 i t e m s had f a i l u r e s :
1 of
4 i n __main__ . f i b
∗∗∗ T e s t F a i l e d ∗∗∗ 1 f a i l u r e s .
’’’
Erweitert man die Fibonacci-Funktion nun um eine Überprüfung, ob n kleiner als Null
ist und wirft in dem Fall die Exception ValueError mit der Nachricht "Keine negativen Zahlen.", so erhält man bei Ausführung keine Fehlermeldung mehr. Man sieht gar
nichts, da im Allgemeinen nur fehlgeschlagene Tests angezeigt werden (führt man das
Modul mit der Option -v aus, so werden auch Meldungen zu erfolgreichen Testfällen
ausgegeben).
Da Docstrings der Dokumentation von Programmcode dienen, sollten in diesen allerdings
nur kleine und erklärende Beispiele vorkommen, damit sie auch für die Dokumentation zu
gebrauchen sind. Normalerweise eignen sich Docstring-Tests jedoch nicht zum generellen
Testen eines Moduls.
2.5.2 Modul unittest
Im Gegensatz zum doctest-Verfahren werden hier die Testfälle in einem eigenen Modul,
also getrennt von der Programmlogik, definiert, sodass die Dokumentation und der Programmcode sauber bleiben. Hierfür muss eine Klasse erstellt werden, die von der Klasse
unittest.TestCase erbt. In dieser werden entsprechende Testmethoden definiert. Üblicherweise testet eine Testklasse nicht mehr als ein Modul. Ein unittest-Modul, das
beinahe die gleichen Tests durchführt wie soeben die Docstring-Tests, sieht dann wie
folgt aus.
15
2 Konzepte und Struktur
Fibonacci - unittest
1
import u n i t t e s t , f i b
2
3
c l a s s FibTest ( u n i t t e s t . TestCase ) :
4
5
6
7
8
def t e s t C a l c u l a t i o n ( s e l f
self . assertEqual ( fib .
self . assertEqual ( fib .
self . assertEqual ( fib .
):
f i b ( 4 ) , 6)
f i b ( 1 5 ) , 987)
f i b ( 2 5 ) , 121393)
9
10
11
def t e s t E x c e p t i o n ( s e l f ) :
s e l f . a s s e r t R a i s e s ( V a l u e E r r o r , f i b . f i b , −2)
12
13
14
i f (__name__ == "__main__" ) :
u n i t t e s t . main ( )
Beim Testen der vierten Fibonacci-Zahl ist leider ein Fehler unterlaufen und Eingaben
kleiner als Null werden noch nicht behandelt, sodass das Ausführen zu Folgendem führt.
Fibonacci - unittest-Testergebnisse
1
2
3
4
5
6
7
8
’’’
FE
================================================================
ERROR : t e s t E x c e p t i o n ( __main__ . F i b T e s t )
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
T r a c e b a c k ( most r e c e n t c a l l l a s t ) :
...
R u n t i m e E r r o r : maximum r e c u r s i o n d e p t h e x c e e d e d i n c o m p a r i s o n
9
10
11
12
13
14
15
16
================================================================
FAIL : t e s t C a l c u l a t i o n ( __main__ . F i b T e s t )
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
T r a c e b a c k ( most r e c e n t c a l l l a s t ) :
F i l e " f i b _ u n i t t e s t . py " , l i n e 6 , i n t e s t C a l c u l a t i o n
s e l f . a s s e r t E q u a l ( f i b . f i b ( 4 ) , 6)
A s s e r t i o n E r r o r : 5 != 6
17
18
19
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Ran 2 t e s t s i n 0 . 0 1 5 s
20
21
22
FAILED ( f a i l u r e s =1, e r r o r s =1)
’’’
16
2 Konzepte und Struktur
Behebt man nun den fehlerhaften Test und erweitert das Modul fib, um die Überprüfung
auf Eingaben kleiner als Null, so laufen die Tests erfolgreich durch und es ergibt sich
folgende Ausgabe.
Fibonacci - unittest-Testergebnisse (ohne Fehler)
1
2
3
4
’’’
..
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Ran 2 t e s t s i n 0 . 0 8 4 s
5
6
7
OK
’’’
Muss man komplexere Module testen, zum Beispiel eine Klasse, so ist es eventuell nötig,
gewisse Initialisierungen zu machen, bevor die eigentlichen Tests durchlaufen können.
Auch kann es notwendig sein, nach Ablauf aller Tests abschließenden Code zu schreiben.
Hierfür gibt es, wie aus Java bekannt, die Methoden setUp() und tearDown(), die
ganz zu Beginn beziehungsweise ganz am Schluss ausgeführt werden. Sollte es innerhalb
dieser Methoden dazu kommen, dass eine Exception ausgelöst wird, so wird der Test
abgebrochen und dies als Fehler im Testbericht eingetragen. Außerdem gibt es noch
weitaus mehr assert-Anweisungen als hier vorgestellt, um Testergebnisse zu überprüfen.
2.6 Besonderheiten
2.6.1 Annotationen
Sogenannte Annotations sind Anmerkungen, die bei einer Funktionsdefinition jedem
Parameter und dem Rückgabewert hinzugefügt werden können. Syntaktisch sieht dies
für das Fibonacci-Beispiel von vorhin folgendermaßen aus. Hier wurde der Parameter n
und der return-Wert um eine Typ-Annotation erweitert.
Annotations - Syntax
1
2
3
4
5
6
7
def f i b ( n : i n t ) −> i n t :
i f ( n == 0 ) :
return 1
e l i f ( n == 1 ) :
return 1
else :
r e t u r n f i b ( n−1) + f i b ( n−2)
Eine solche Annotation darf ein beliebiger Python-Ausdruck sein und steht zur Laufzeit
in dem Magic-Attribut __annotations__ des Funktionsobjektes fib zur Verfügung.
17
2 Konzepte und Struktur
Hierbei handelt es sich um ein Dictionary, wobei ein Parametername ein Schlüssel und
die dazugehörige Annotation der jeweilige Wert ist. Das __annotations__-Dictionary
zu obigem Beispiel sähe also wie folgt aus.
Annotation-Dictionary
1
2
3
4
5
f i b . __annotations__ =
{
"n" : int ,
" return " : int
}
Somit kann der Programmierer beim Definieren einer Funktion Informationen hinterlegen, die er zur Laufzeit für seine Zwecke benutzen möchte. Versieht man die Parameter wie hier mit Typ-Annotationen, so könnte man zur Laufzeit vor der Ausführung
des Funktionscodes eine Typprüfung durchführen. Somit hätte man die Möglichkeit die
Funktionsausführung vorzeitig mit einer TypeError-Exception abzubrechen, falls ein
Parameter Instanz eines nicht passenden Datentyps ist. Außerdem ist es für andere Programmierer beim Lesen des Codes schneller ersichtlich, wofür gewisse Parameter gedacht
sind oder welchen Typ sie haben sollen.
Annotations ändern nichts an der Funktionslogik, greifen also nicht in die Ausführung
der Funktion ein, womit die Annotations in Python zum Programmierparadigma der
aspektorientierten Programmierung zählen.
18
3 Technische Unterstützung
3.1 Compiler, Interpreter und Entwicklungsumgebungen
Obwohl Python zwar häufig als Skriptsprache verwendet wird und viele Sprachelemente
heutiger Skriptsprachen implementiert, handelt es sich dennoch um eine interpretierte
Programmiersprache. Wie auch bei Java, erzeugt ein Compiler zunächst aus dem QuellCode den sogenannten Byte-Code, der dann in der virtuellen Maschine, dem PythonInterpreter, ausgeführt werden kann.
Für Python gibt es zahlreiche Entwicklungsumgebungen. Eine davon ist IDLE (Integrated Development Environment, s. http://www.python.org/idle). Sie bietet sowohl unter
Windows als auch unter Unix-Systemen eine grafische Benutzeroberfläche mit einer Shell
und einem hauseigenen Editor. Sie ist vollständig in Python implementiert. IDLE ist in
der Lage Code-Schlüsselwörter hervorzuheben (Syntax-Highlighting) und unterstützt die
automatische Codevervollständigung.
Neben IDLE gibt es beispielsweise noch das Eclipse-Plugin PyDev (s. http://pydev.org).
Mit diesem kann man prinzipiell genau so wie man es bei Java-Projekten gewohnt ist,
Python-Applikationen schreiben. Es wird Syntax-Highlighting und Codevervollständigung unterstützt und, wie in IDLE, lässt sich ein Modul ausführen, dessen eventuelle
Ausgabe in der programmeigenen Konsole beziehungsweise Shell angezeigt wird.
3.2 Werkzeuge und Bibliotheken
3.2.1 Interaktive Umgebung
Der Python-Interpreter kann auch ohne Argumente, also ohne die Angabe einer PythonQuelltext-Datei, gestartet werden. Tut man dies, so gelangt man in den interaktiven Modus (auch interaktive Umgebung). In diesem ist es möglich beliebigen PythonCode zu schreiben und sich Ergebnisse dieser Eingaben direkt anzuschauen (vgl. GHCI
für Haskell). Dies kann man nutzen, um kleine Beispiele, Ideen oder Konzepte schnell
zu testen. Es ist jedoch unkomfortabel und ungeeignet den interaktiven Modus zum
Schreiben richtiger Programme zu nutzen. Im interaktiven Modus wird nämlich kein
Syntax-Highlighting unterstützt. Außerdem ist es nicht möglich, einzelne Zeilen des
eingegeben Codes zu bearbeiten, sondern es müsste der gesamte Code noch einmal
eingegeben werden.
19
3 Technische Unterstützung
3.2.2 Standardbibliothek
Python macht es dank seiner umfangreichen Standardbibliothek möglich, mit wenig
Aufwand recht effiziente umfangreiche Programme in unterschiedlichsten Bereichen zu
schreiben, ohne übermäßig viel Quelltext zu erzeugen. Die Standardbibliothek bietet
neben den üblichen Bibliotheken für Mathematik (Modul math) oder Datum und Zeit
(Modul time) auch Bibliotheken zum Programmieren von parallelen Programmen (Module _thread und threading), für die Netzwerkkommunikation (Modul socket), die
Datenspeicherung (Module gzip und xml) sowie für das Debugging (Module inspect
und logging). Auch eine Bibliothek, die als Schnittstelle zum Betriebssystem dient, wird
angeboten (Module os, shutil, platform und sys).
3.3 Portabilität
Da Python wie Java zur Ausführung einen Interpreter, also eine virtuelle Maschine,
benötigt, ist Python sehr portabel. Man kann hier sogar von Plattformunabhängigkeit
sprechen, da es mindestens für die drei bekanntesten Betriebssysteme (Windows, Mac,
Linux) Interpreter gibt.
Es existieren verschiedene Python-Interpreter, wobei es sich bei CPython (auch cPython,
s. http://www.python.org) um den standardmäßig installierten und am häufigsten verwendeten handelt. Dieser ist die Referenzimplementation des Python Interpreters, wurde
in C geschrieben und wird als Open-Source-Software von der PSF entwickelt [4].
Es existieren noch weitere Implementationen von Python-Interpretern, zu diesen zählt
unter anderem PyPy (s. http://pypy.org).
20
4 Zusammenfassung und Fazit
Diese Seminararbeit hat einen kleinen Überblick über die Programmiersprache Python
gegeben. Hierbei wurden sowohl die Geschichte der Sprache als auch einige ausgewählte
Features betrachtet. Zunächst wurden Grundlagen zur Sprache vorgestellt und anschließend einige Konzepte der Sprache behandelt. Die untersuchten Konzepte waren die funktionale und objektorientierte Programmierung in Python. Auch das Exceptionhandling,
das automatisierte Testen und Annotationen wurden besprochen. Außerdem wurden
Entwicklungsumgebungen und Werkzeuge für Python vorgestellt sowie besondere Eigenschaften der Sprache, wie zum Beispiel ihre Portabilität. Diese Aspekte der Programmiersprache Python zeigen bereits einige Vor- und Nachteile.
Einerseits ist an Pythons Syntax zu kritisieren, dass einem als Programmierer vorgegeben
wird, wie man seinen Code zu formatieren hat. Dies ist zwar gerade für Anfänger sicherlich sinnvoll und lehrreich, wird jedoch von vielen fortgeschrittenen Programmieren als
störend empfunden. Beispielsweise können dadurch Einrückungen, die aufgrund der Optik gemacht werden, nicht vorgenommen werden, da sie zu einem Syntax-Fehler führen.
Weiterhin ist es unschön und redundant jeder Methode einer Klasse explizit die Referenz
self übergeben zu müssen. Außerdem ist Python nicht für zeitkritische Systeme gedacht,
da Programme auf einer virtuellen Maschine ausgeführt werden, was Leistung und Zeit
kostet, wie dies von Java bereits bekannt ist.
Andererseits bietet Python die Möglichkeit leicht lesbaren und mächtigen Code zu schreiben, der gerade im Vergleich zu anderen Programmiersprachen wie Java deutlich kürzer
sein kann, was vor allem an der umfangreichen Standardbibliothek liegt, denn diese spart
einem viel Code, den man in anderen Programmiersprachen teilweise selbst schreiben
muss. Dies trägt zur großen Flexibilität von Python bei, wodurch Python in vielen
Anwendungsgebieten eingesetzt werden kann. Weiterhin ist Python leicht um weitere
Bibliotheken (von Drittanbietern oder sogar eigene) erweiterbar, was wiederum zur Flexibilität und Mächtigkeit von Python beiträgt. Aufgrund der einfachen Syntax ist Python
leicht zu erlernen, was es, zusammen mit der automatischen Speicherverwaltungen, auch
weniger erfahrenen Programmierern möglich macht, schnell komplexe Programme zu
schreiben. Auch ist es wegen der Portabilität von Python leicht möglich, plattformunabhängige Applikationen zu schreiben.
Schlussendlich ist Python zwar keine so weit verbreitete Programmiersprache wie es
Java ist, sie hat aber ihre Anhänger. Meiner Ansicht nach wurde ihr volles Potential
sowohl für kommerzielle Zwecke als auch für Open Source Projekte bisher noch nicht
erkannt.
21
Literaturverzeichnis
[1] Guido van Rossum. Website. Online unter http://de.wikipedia.org/wiki/Guido_
van_Rossum;besucht am 18.01.2013.
[2] Johannes Ernesti; Peter Kaiser. Python3 Das umfassende Handbuch. Galileo Press,
2012. 3., aktualisierte und erweiterte Auflage.
[3] Duck-Typing.
Website.
Online unter http://de.wikipedia.org/wiki/
Duck-Typing;besucht am 18.01.2013.
[4] CPython. Website. Online unter http://en.wikipedia.org/wiki/CPython und
http://www.python.org;besucht am 04.02.2013.
[5] Python Dokumentation.
Website.
3/;besucht am 02.12.2012.
Online unter http://docs.python.org/
[6] Python (Programmiersprache). Website. Online unter http://de.wikipedia.org/
wiki/Python_%28Programmiersprache%29;besucht am 18.01.2013.
[7] Vorlesung der Uni Osnabrück. Website. Online unter http://www.vorlesungen.
uni-osnabrueck.de/informatik/altprog00/python/node1.html;besucht
am
02.12.2012.
[8] Die Programmiersprache Python (TU Chemnitz). Website. Online unter http:
//www-user.tu-chemnitz.de/~hot/PYTHON/;besucht am 02.12.2012.
22
Herunterladen