Grundkurs Python3
Grundkurs Python3
Release 0.1.2d
Aktualisiert am 02.12.2018
Bernhard Grotz
http://www.grund-wissen.de
Dieses Buch wird unter der Creative Commons License (Version 3.0, by-nc-sa) veröffent-
licht. Alle Inhalte dürfen daher in jedem beliebigen Format vervielfältigt und/oder wei-
terverarbeitet werden, sofern die Weitergabe nicht kommerziell ist, unter einer gleichen
Lizenz erfolgt, und das Original als Quelle genannt wird. Siehe auch:
Unabhängig von dieser Lizenz ist die Nutzung dieses Buchs für Unterricht und Forschung
(§52a UrhG) sowie zum privaten Gebrauch (§53 UrhG) ausdrücklich erlaubt.
Der Autor erhebt mit dem Buch weder den Anspruch auf Vollständigkeit noch auf Feh-
lerfreiheit; insbesondere kann für inhaltliche Fehler keine Haftung übernommen werden.
Die Quelldateien dieses Buchs wurden unter Linux mittels Vim und Sphinx, die enthal-
tenen Graphiken mittels Inkscape erstellt. Der Quellcode sowie die Original-Graphiken
können über die Projektseite heruntergeladen werden:
http://www.grund-wissen.de
Bei Fragen, Anmerkungen und Verbesserungsvorschlägen bittet der Autor um eine kurze
Email an folgende Adresse:
info@grund-wissen.de
Bernhard Grotz
Inhaltsverzeichnis
Installation 1
Installation von Python3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Installation von Ipython3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Virtuelle Umgebungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Einführung 4
Interaktiver Modus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Python-Skripte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Datentypen 10
None – Der Nichts-Typ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Numerische Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
str – Zeichenketten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
list und tuple – Listen und Tupel . . . . . . . . . . . . . . . . . . . . . . . . . 19
set und frozenset – Mengen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
dict – Wörterbücher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
file – Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Kontrollstrukturen 31
if, elif und else – Fallunterscheidungen . . . . . . . . . . . . . . . . . . . . . 31
while und for – Schleifen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
pass – Die Platzhalter-Anweisung . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Funktionen 35
Definition eigener Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Optionale Argumente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Veränderliche und unveränderliche Argumente . . . . . . . . . . . . . . . . . . . 37
Lambda-Ausdrücke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Builtin-Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
i
Module und Pakete 54
Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Pakete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Design Patterns 71
Erzeugungsmuster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Strukturmuster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Verhaltensmuster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Scientific Python 78
Mathematik mit Standard-Modulen . . . . . . . . . . . . . . . . . . . . . . . . . 78
ipython – eine Python-Entwicklungsumgebung . . . . . . . . . . . . . . . . . . 82
matplotlib – ein Plotter für Diagramme . . . . . . . . . . . . . . . . . . . . . . 88
numpy – eine Bibliothek für numerische Berechnungen . . . . . . . . . . . . . . . 101
pandas – eine Bibliothek für tabellarische Daten . . . . . . . . . . . . . . . . . . 108
sympy – ein Computer-Algebra-System . . . . . . . . . . . . . . . . . . . . . . . 118
Beispielaufgaben für Scipy, Sympy und Pandas . . . . . . . . . . . . . . . . . . . 122
Anhang 145
Schlüsselwörter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Standardfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Wichtige Standard-Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
ASCII-Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
Links 178
Stichwortverzeichnis 180
ii
Installation
Bei neuen Linux-Versionen ist Python in den Versionen 2.7 und 3.5 bereits vorinstalliert.
Auf älteren Systemen kann es hingegen notwendig sein, die aktuelle (und sehr empfehlens-
werte) Version 3 von Python nachträglich zu installieren. Hierzu sollten folgende Pakete
mittels apt installiert werden:
Das zuletzt genannte Programm pip3 erlaubt es, zusätzliche Erweiterungen (sofern diese
nicht auch über apt installierbar sind) mittels folgender Syntax zu installieren:
Dabei werden automatisch alle bekannten Python-Repositories durchsucht und die aktuel-
le Version installiert. Mit der Option -U („update“) wird eine eventuell bereits vorhandene,
nicht mehr aktuelle Version eines Pakets durch die neueste Version ersetzt. Beispielsweise
kann so mittels pip3 -U Sphinx die neueste Version des Python-Dokumentationssystems
Sphinx installiert werden. Alternativ kann auch in den gewöhnlichen Linux-Paketquellen
mittels apt nach einem entsprechenden Python-Paket gesucht beziehungsweise dieses in-
stalliert werden.
Anstelle des „normalen“ Python-Interpreters, der sich durch Aufruf von python3 ohne
weitere Argumente starten lässt, sollte bevorzugt ipython3 verwendet werden. Neben
einer automatischen Vervollständigung von Modul-, Klassen- und Funktionsnamen bei
Drücken der Tab-Taste bietet Ipython eine interaktive Syntax-Hilfe und weitere hilfreiche
Funktionen.
Ipython kann als Shell-Version anschließend mittels ipython3, die graphische Oberfläche
mittels ipython3 qtconsole gestartet werden.
1
Virtuelle Umgebungen
# Oder:
Der Unterschied zwischen diesen beiden Varianten liegt darin, dass die erste Symlinks auf
bereits installierte Python-Pakete setzt (platzsparend, aufbauend auf dem bestehenden
System), die zweite hingegen eine vollständig neue Umgebung schafft (nützlich, wenn
ein installiertes Paket für ein konkretes Projekt modifiziert werden soll, beispielsweise
Sphinx).
Die virtuelle Umgebung kann dann aus dem Projektverzeichnis heraus folgendermaßen
aktiviert werden:
Alle Paket-Installationen, die bei einer aktiven virtuellen Umgebung vorgenommen wer-
den, haben nur Auswirkung auf diese Umgebung; zunächst ist überhaupt kein Zusatzpaket
installiert. Mittels pip3 install paketname können wie gewohnt Pakete installiert wer-
den:
Gegebenenfalls muss, beispielsweise bei der lokalen Installation von Sphinx, anschlie-
ßend hash -r eingegeben werden, damit der „Suchpfad“ aktualisiert und die Python-
Programme beim Aufruf auch lokal gefunden werden.
Durch Eingabe von deactivate in dem Shell-Fenster wird die virtuelle Umgebung wieder
beendet:
2
Links
Virtualenv-Tutorials:
https://realpython.com/python-virtual-environments-a-primer/
https://www.simononsoftware.com/virtualenv-tutorial-part-2/
3
Einführung
Python ist eine Programmiersprache, die einfach zu erlernen ist und ein schnelles Entwi-
ckeln von Programmen ermöglicht. Aufgrund der verhältnismäßig hohen Lesbarkeit und
einiger hilfreicher Mathematik-Module wird Python auch im akademischen und schuli-
schen Bereich häufig verwendet.
Interaktiver Modus
Um Python im interaktiven Modus zu starten, ruft man den Interpreter in einer Shell
ohne weitere Parameter auf:
python3
Nach dem Eingabe-Prompt >>> kann beliebiger Python-Code eingegeben werden. Drückt
man die Enter-Taste, so wird dieser unmittelbar ausgeführt. So lässt sich der Python-
1
Interpreter beispielsweise als besserer Taschenrechner benutzen:
>>> 5 + 3 # Addition
8
>>> 7 * 21 # Multiplikation
147
>>> 15 ** 2 # Potenz
225
>>> 14 / 80 # Division
0.175
1 Neben der gewöhnlichen Division mit / kann auch mit // eine Ganzzahl-Division durchgeführt
werden. Bei einer solchen Division wird der Divisionsrest weggelassen und stattdessen die nächst kleinere
können auf einmal durch die Funktion divmod() ausgegeben werden; beispielsweise ergibt divmod(17,5)
Wurzeln können entweder als Potenzen mit einer rationalen Zahl als Exponent oder mittels der Funktion
4
Interne Hilfe
Jeder Python-Interpreter bietet dem Nutzer im interaktiven Modus die Möglichkeit, wei-
tere Informationen oder Dokumentationen zu Python-Objekten (Funktionen, Operatoren
usw.) anzuzeigen. Um Hilfe zu einem beliebigen Python-Objekt zu erhalten, kann die
Funktion help() genutzt werden:
Ebenso können Variablen an die Help-Funktion übergeben werden, um Hilfe zum jewei-
ligen Objekttyp zu erhalten. Mit type(object_name) kann der Typ eines Objekts, mit
id(variable_name) zusätzlich die aktuelle Speicheradresse des Objekts angezeigt wer-
den.
Python-Skripte
Python-Code, der bei der interaktiven Benutzung des Interpreters eingegeben werden
kann, kann in gleicher Form ebenso in Textdateien („Skripte“), üblicherweise mit der
Endung .py, geschrieben werden. Derartige Dateien können entweder in einer interakti-
ven Python-Sitzung mittels execfile("skriptname.py") oder folgendermaßen in einem
Shellfenster aufgerufen werden:
python3 skriptname.py
Beim Aufruf eines Skripts wandelt Python den Quellcode in so genannten „Bytecode“
um und führt diesen aus. Wird eine Quellcode-Datei anderen Dateien importiert, so legt
Python automatisch eine zusätzliche Datei skriptname.pyc im gleichen Verzeichnis an.
Es ist auch möglich, eine Skriptdatei direkt als ausführbare Datei aufzurufen. Dazu fügt
man zunächst folgende Zeilen am Anfang der Skriptdatei ein:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
Die erste Zeile wird „Shebang“ genannt und gibt den Pfad zum Python-Interpreter an, der
beim Aufruf des Skripts geladen werden soll; die zweite Zeile gibt an, welcher Zeichensatz
in der Datei verwendet wird (utf-8 ist Standard unter Linux).
Mit der obigen Ergänzung kann die Skriptdatei dann mittels chmod ausführbar gemacht
werden:
chmod +x skriptname.py
Das Skript kann damit mittels ./skriptname.py aus dem aktuellen Pfad heraus oder
allgemein mittels pfad-zum-skript/skriptname.py aufgerufen werden. Soll es benut-
zerweit aufrufbar sein, so empfiehlt es sich, einen Symlink zum Skript im Verzeichnis
5
~/bin zu erstellen und dieses durch folgenden Eintrag in der ~/.bashrc zum Systempfad
2
hinzuzufügen:
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
export PATH;
fi
Das Schreiben von Code-Dateien ist in Python gegenüber der interaktiven Benutzung des
Interpreters unter anderem deshalb von Vorteil, da Python beispielsweise bei der Definiti-
on von Funktionen und Kontrollstrukturen Einrückungen statt Klammern zur Gliederung
des Quellcodes verwendet.
Gute Texteditoren machen den Umgang mit Einrückungen einfach und bieten obendrein
Vorteile wie Syntax-Highlighting, Eingabe-Vervollständigungen, Snippets, usw. Bei Ver-
wendung von Vim und des Vicle-Plugins ist es zudem auch während des Schreibens der
Textdateien möglich, einzelne Code-Zeilen oder auch ganze Code-Blöcke an eine laufen-
de Interpreter-Sitzung zu senden; so können die Vorteile des Interpreters (beispielsweise
Ausgabe von Variablenwerten und Zwischenergebnissen) und des Texteditors kombiniert
werden.
Umfangreichere Skripte sollten zur besseren Lesbarkeit mit Kommentaren versehen wer-
den. Kommentare werden durch das Raute-Symbol # eingeleitet und gehen bis zum Ende
der Zeile.
Variablen
Eine wichtige Eigenschaft von Computer-Programmen ist, dass sie nahezu beliebig viele
Werte und Zeichen in entsprechenden Platzhaltern („Variablen“) speichern und verarbeiten
können. Auf so gespeicherte Werte kann man im Verlauf des Programms wieder zugreifen
und/oder den Variablen neue Werte zuweisen.
In Python können Variablennamen aus Groß- und Kleinbuchstaben, Ziffern und dem
Unterstrich-Zeichen bestehen, wobei sie nicht mit einer Ziffer beginnen dürfen. Bei der
Benennung von Variablen ist außerdem auf Groß- und Kleinschreibung zu achten, bei-
spielsweise bezeichnen var_1 und Var_1 zwei unterschiedliche Variablen. Zudem dürfen
keine von der Programmiersprache reservierten Wörter als Variablennamen verwendet
werden (beispielsweise and, or, is, type, key usw.)
Ein Wert kann in einer Variablen mittels des Zuweisungs-Operators = gespeichert werden:
var_1 = "Hallo!"
var_2 = 42
In Python dient das =-Zeichen somit ausschließlich der Zuweisung von Werten; für einen
Werte-Vergleich muss hingegen das doppelte Istgleich-Zeichen == verwendet werden.
6
Im interaktiven Modus wird der Wert einer Variablen angezeigt, indem man deren Namen
in einer neuen Zeile eingibt und Enter drückt. In Skripten werden die Werte von Variablen
oftmals mittels der Funktion print() angezeigt:
print(var_1)
print(var_2)
Bei der Verwendung von print() werden dabei die Variable als Zeichenkette ausgegeben.
Variablen werden in Python dynamisch typisiert, das heißt in der gleichen Variablen
können im Verlauf des Programms verschiedene Datentypen zugewiesen werden.
Operatoren
Bei der Auswertung einzelner mathematischer Ausdrücke gilt wie üblich „Punkt vor
Strich“. Um eine andere Auswertungsreihenfolge zu bewirken, können einzelne Ausdrücke,
wie in der Mathematik üblich, durch runde Klammern zusammengefasst werden.
Für die in Python üblichen Operatoren ist eine allgemein gültige „Rangfolge“ für die
Auswertungsreihenfolge festgelegt. In der folgenden Tabelle sind die Operatoren mit der
höchsten Priorität stehen oben, gleichberechtigte Operatoren (die von links nach rechts
3
ausgewertet werden) stehen in der gleichen Zeile.
Operator Bedeutung
() Gruppierung
x[], x.attribute Listenzugriff (siehe Listen ), Objekteigenschaft
** Potenz
+ und - Positives beziehungsweise negatives Vorzeichen ei-
ner Zahl
*, /, //, % Multiplikation, Division, Ganzzahl-Division, Rest
(Modulo)
==, <=, <, !=, >=, Wertevergleich (gleich, kleiner als oder gleich, klei-
>, is, is not, in, ner als, ungleich, größer als oder gleich, größer als),
not in Identitätsvergleich, Test auf Mengenzugehörigkeit
not Logisches Nicht
and Logisches Und
or Logisches Oder
2 ** 2 ** 3 == 2 ** 8 == 256.
biniert, so werden diese von rechts nach links ausgewertet. Somit gilt
7
Kombinierte Zuweisungsoperatoren
+= Erhöhung der links stehenden Variable um Wert auf der rechten Seite
-= Erniedrigung der links stehenden Variable um Wert auf der rechten
Seite
*= Multiplikation der links stehenden Variable mit Wert auf der rechten
Seite
/= Division der links stehenden Variable durch Wert auf der rechten Seite
//= Ganzzahlige Division der links stehenden Variable durch Wert auf der
rechten Seite
//= Rest bei ganzzahliger Division der links stehenden Variable durch Wert
auf der rechten Seite
**= Potenzieren einer Variable mit Wert auf der rechten Seite
Beispielsweise kann auf diese Weise mit x **= 2 der aktuelle Wert der Variablen x qua-
driert werden. Für Zeichenketten existieren nach dem gleichen Prinzip die Operatoren
+= und *=, die zum String auf der linken Seite einen weiteren String anhängen bzw. den
String auf der linken Seite mehrfach wiederholt aneinander reihen.
Kombinierte Vergleichsoperatoren
Eine weitere Besonderheit in Python liegt darin, dass mehrere Vergleichsoperatoren un-
mittelbar miteinander kombiniert werden können; beispielsweise kann wie in der Mathe-
matik 1 < 2 < 3 geschrieben werden. Die einzelnen Teilausdrücke muss man sich dabei
mit einem and-Operator verbunden denken, denn der Ausdruck ist genau dann wahr,
wenn 1 < 2 and 2 < 3 gilt.
Die „Verkettungsregel“ gilt für alle Vergleichsoperatoren, auch wenn das Ergebnis nicht
immer mit der eigenen Erwartung übereinstimmen muss. Beispielsweise könnte man im
Fall1 == 2 < 3 das Ergebnis True erwarten, wenn man sich die gleichwertigen Operato-
ren von links nach rechts ausgewertet denkt, denn 1 == 2 ist False und zudem ist False
< 3. Die Aussage liefert in Python jedoch False als Ergebnis, denn sie wird als 1 == 2
and 2 < 3 interpretiert, und zwei mit and verknüpfte Aussagen ergeben nur dann ein
wahres Ergebnis, wenn beide Aussagen wahr sind.
Im Zweifelsfall können die einzelnen Teilaussagen jederzeit mit Hilfe von runden Klam-
mern gruppiert werden, um eine ungewollte Auswertungsreihenfolge zu vermeiden.
Bedingte Wertzuweisung
8
Operator etwa x = condition ? a : b, was bedeutet, dass der Variablen 𝑥 der Wert a
zugewiesen wird, wenn die Bedingung condition wahr ist; andernfalls wird der Variablen
x der Wert b zugewiesen.
In Python lautet das entsprechende Sprachkonstrukt folgendermaßen:
x = a if condition else b
Auch hier wird zunächst die Bedingung condition geprüft. Wenn diese den Wert True
ergibt, so wird der Variablen x der Wert a zugewiesen, andernfalls der Wert b.
9
Datentypen
Durch den Datentyp None wird in Python beispielsweise symbolisiert, dass eine Variable
keinen Wert beinhaltet. Dies ist beispielsweise sinnvoll, wenn man eine Variable definieren,
ihr aber erst späteren einen konkreten Wert zuweisen will; ein anderer Anwendungsfall
wäre die Rückgabe eines Ergebniswerts bei einer erfolglosen Suche.
Um einer Variablen den Wert None zuzuweisen, gibt man folgendes ein:
var_1 = None
# Test:
print(var_1)
# Ergebnis: None
if var_1 is None:
print('var_1 has no value.')
else:
print('the value of var_1 is ' var_1)
Mittels des Schlüsselworts is wird im obigen Beispiel überprüft, ob var_1 eine Instanz des
Typs None ist. Durch if var_1 is not None kann sichergestellt werden, dass ein Code-
Teil nur dann ausgeführt wird, wenn der Variablen var_1 bereits ein Wert zugewiesen
wurde.
10
Numerische Datentypen
Eine boolesche Variable kann nur True False (falsch) als Werte annehmen.
(wahr) oder
Von Python wird True als 1 beziehungsweise False als 0 interpretiert, so dass sich theo-
retisch auch mit Variablen des Datentyps bool rechnen lässt (beispielsweise ergibt True
+ True den Wert 2).
Der boolesche Wahrheitswert eines beliebigen Ausdrucks kann mittels der Standard-
Funktion bool() ermittelt werden, beispielsweise liefert bool(1) den Wert True.
Um die Anzahl an Ziffern einer int-Zahl zu bestimmen, kann diese mittels str() in
eine Zeichenkette umgewandelt werden; anschließend kann die Länge dieser Zeichenkette
mittels len() bestimmt werden:
num_1 = 58316
str(num_1)
# Ergebnis: '58316'
len(str(num_1))
# Ergebnis: 5
Wird im umgekehrten Fall eine Zahl beispielsweise mittels der Funktion input() einge-
lesen, so liegt sie als Zeichenkette vor; mittels int() ist dann eine Konvertierung in eine
gewöhnliche Zahl möglich.
Bisweilen werden Zahlen auch in einer binären, oktalen oder hexadezimalen Darstellung
verwendet. Um eine dezimale int-Zahl mit einer anderen Zahlenbasis (2, 8 oder 16)
darzustellen, gibt es folgende Funktion:
num_1 = 78829
bin(num_1)
# Ergebnis: '0b10011001111101101'
oct(num_1)
# Ergebnis: '0o231755'
11
(Fortsetzung der vorherigen Seite)
hex(num_1)
# Ergebnis: '0x133ed'
Das Ergebnis sind jeweils Zeichenketten, die mit 0b (binär), 0o (oktal) oder 0x (hexade-
zimal) beginnen. Um eine derartige Zeichenkette wieder in eine gewöhnliche int-Zahl zu
konvertieren, kann man die int()-Funktion nutzen, wobei die ursprüngliche Zahlenbasis
als zweites Argument angegeben werden muss:
int('0b10011001111101101', base=2)
# Ergebnis: 78829
Um die größte beziehungsweise kleinste mindestens zweier Zahlen (int oder float) zu
bestimmen, können die Funktionen min() oder max() genutzt werden:
Der Absolutwert einer int oder float-Zahl kann mittels der Standardfunktion
abs(number) ausgegeben werden.
float – Gleitkommazahlen
Zahlen mit Nachkommastellen werden in Python durch den Datentyp float repräsentiert.
Die Nachkommastellen werden dabei – wie im englischen Sprachraum üblich – nicht durch
ein Komma, sondern durch einen Punkt . von dem ganzzahligen Anteil getrennt. Zudem
ist es möglich, sehr große oder sehr kleine float-Zahlen mittels e oder E in Exponential-
Schreibweise anzugeben. Die Zahl hinter dem e gibt dabei an, um wie viele Stellen der
Dezimalpunkt innerhalb der Zahl verschoben wird.
4.3e5 == 430000
# Ergebnis: True
7.92e-5 == 0.0000792
# Ergebnis: True
Um float-Zahl
eine auf 𝑛 Nachkomma-Stellen zu runden, kann die Funktion
round(float_num, n) genutzt werden. Wird das Argument n weggelassen, wird auf
die nächste ganze Zahl gerundet. Eine Gleitkommazahl float_1 kann ebenso mittels
int(float_1) in eine ganze Zahl umgewandelt werden; dabei werden jedoch eventuell
vorhandene Nachkommastellen abgeschnitten, es also stets die betragsmäßig nächst klei-
nere ganze Zahl als Ergebnis zurück gegeben.
12
complex – Komplexe Zahlen
Komplexe Zahlen bestehen aus einem Realteil und einem Imaginärteil. Der Imaginärteil
1
besteht aus einer reellen Zahl, die mit der imaginären Einheit j multipliziert wird.
Um eine komplexe Zahl zu definieren, gibt man in Python etwa folgendes ein:
z_1 = 4 + 3j
z_2 = 5.8 + 1.5j
Für das Arbeiten mit komplexen Zahlen kann das cmath-Modul aus der Standardbiblio-
thek genutzt werden.
str – Zeichenketten
Zeichenketten („Strings“) sind eine Folge von Zeichen, die wahlweise in einfachen oder
2
doppelten Anführungszeichen geschrieben werden. Nahezu jedes Python-Objekt kann
mittels str(object) in eine Zeichenkette umgewandelt werden, um beispielsweise eine
druckbare Darstellung mittels print() zu ermöglichen.
string_1 = 'Hallo'
string_2 = 'Welt!'
string_3 = str(539) # Ergebnis: '539'
Zeichenketten können mittels + miteinander kombiniert werden. Möchte man eine Zei-
chenkette beliebiger Länge in mehrfacher Wiederholung, so kann diese mittels * und einer
ganzzahligen Zahl vervielfacht werden. Da Zeichenketten in Python (wie Tupel ) unver-
änderbar sind, wird bei den obigen Beispielen stets eine neue Zeichenkette erzeugt. Die
ursprüngliche Zeichenkette bleibt jeweils unverändert:
string_1 * 3
# Ergebnis: 'HalloHalloHallo'
len('Hallo Welt')
# Ergebnis: 10
1 In der Mathematik wird die imaginäre Einheit meist mit 𝑖 bezeichnet, in der Elektrotechnik wird
hingegen oft 𝑗 verwendet. In Python kann sowohl j als auch J als Symbol für die imaginäre Einheit
geschrieben werden.
2 Python behandelt einfache und doppelte Anführungszeichen gleichwertig, anders als beispielsweise
die Linux-Shell. Innerhalb eines Strings, der in einfache Anführungszeichen gesetzt wird, können doppelte
Sollen einfache Anführungszeichen in einem String vorkommen, der ebenfalls durch einfache Anfüh-
\
rungszeichen begrenzt ist, so muss vor die inneren Anführungszeichen jeweils ein Backslash ( ) als Escape-
13
Zur besseren Lesbarkeit sollten Code-Zeilen allgemein nicht mehr als 80 Zeichen lang sein.
Lange Zeichenketten können allerdings in der nächsten Zeile fortgesetzt werden, wenn
die vorangehende Zeile mit einem einzelnen Backslash \ als Zeile-Fortsetzungs-Zeichen
abgeschlossen wird:
long_string = 'Das ist eine lange Zeichenkette, die für eine bessere \
Lesbarkeit über zwei Zeilen verteilt geschrieben wird.'
Durch den Backslash werden also beide Zeilen zu einer logischen Einheit verbunden; hinter
dem Backslash darf allerdings kein Kommentarzeichen stehen.
Zeichen Bedeutung
\t Tabulator
\n Newline (Zeilenumbruch)
\r Carriage Return
\\ Backslash
\' Einfaches Anführungszeichen
\" Doppeltes Anführungszeichen
\xnn Sonderzeichen (ASCII ), repräsentiert durch eine zweistellige Hexadezi-
malzahl, beispielsweise \xe4
\unnnn Sonderzeichen (16-bit-Unicode), repräsentiert durch eine vierstellige He-
xadezimalzahl, beispielsweise \u7fe2
Möchte man das Interpretieren der obigen Sonderzeichen unterbinden, kann dies durch
ein vorangestelltes r („raw“) geschehen; beispielsweise wird in r'a\tb' das \t nicht als
Tabulator-Zeichen interpretiert.
example[0]
(continues on next page)
14
(Fortsetzung der vorherigen Seite)
# Ergebnis: 'H'
example[1]
# Ergebnis: 'a'
example[-2]
# Ergebnis: 'l'
example[-1]
# Ergebnis: 't'
Der Index-Operator kann ebenso genutzt werden, um Bereiche („Slices“) einer Zeichenkette
auszugeben. Hierzu werden in den eckigen Klammern zwei Index-Zahlen n_1 und n_2
durch einen Doppelpunkt getrennt angegeben. Es muss dabei allerdings beachtet werden,
dass in Python bei Bereichsangaben die obere Grenze nicht im Bereich eingeschlossen ist:
example[0:5]
# Ergebnis: 'Hallo'
example[6:-1]
# Ergebnis: 'Wel'
example[6:]
# Ergebnis: 'Welt'
Lässt man von der Bereichsangabe die Zahl vor oder nach dem Doppelpunkt weg, so wird
die Zeichenkette von Beginn an beziehungsweise bis zum Ende ausgegeben.
Bei der Verwendung von Slices kann optional noch ein dritter Parameter angegeben wer-
den, der die „Schrittweite“ festlegt, also angibt, jedes wie vielte Zeichen ausgewählt werden
soll:
example[::2]
# Ergebnis: 'HloWl'
Wird für die Schrittweite ein negativer Wert angegeben, so wird der String von hinten
nach vorne abgearbeitet.
String-Funktionen
Für Zeichenketten gibt es in Python einige Funktionen, die in der Form zeichenkette.
funktionsname() angewendet werden können.
15
Suchen von Teilstrings
Mittels des in-Operators kann geprüft werden, ob ein Teilstring in einer anderen Zeichen-
kette enthalten ist:
'all' in 'Hallo'
# Ergebnis: True
Möchte man eine Zeichenkette nicht nur hinsichtlich der Existenz eines Teilstrings prü-
fen, sondern auch wissen, wie oft dieser darin enthalten ist, kann die Funktion count()
verwendet werden:
'Hallo'.count('l')
# Ergebnis: 2
Der Funktion count() können als weitere Argumente eine Start- und eine Stopp-Position
übergeben werden, wenn nicht die ganze Zeichenkette, sondern nur ein bestimmter Ab-
schnitt durchsucht werden soll:
# Anzahl des Buchstabens 'l' in den ersten drei Buchstaben von 'Hallo':
'Hallo'.count('l', 0, 3)
# Ergebnis: 1
Wie allgemein in Python üblich, wird bei Bereichsangaben die untere Grenze ins Intervall
aufgenommen, die obere nicht; im obigen Beispiel werden daher nur die drei Indexnum-
mern 0, 1 und 2 geprüft. Mit der gleichen Sytanx kann mittels der Funktion find()
die Index-Position des ersten Vorkommens eines Teilstrings innerhalb der Zeichenkette
angezeigt werden:
'Hallo'.find('l')
# Ergebnis: 2
'Hallo'.find('l', 2, 4)
# Ergebnis: 3
Soll die Suche nicht „von links“, sondern „von rechts“ aus erfolgen, kann die Funktion
rfind() genutzt werden; sie gibt als Ergebnis den Index des letzten Vorkommens des
angegebenen Teilstrings zurück. Wird der gesuchte String im Zielstring nicht gefunden,
liefern die Funktionen find() und rfind() den Wert -1 als Ergebnis zurück.
Soll nur die Endung einer Zeichenkette untersucht werden, beispielsweise bei der Prü-
fung eines Dateityps, so kann anstelle der Funktion rfind() noch besser die Funktion
endswith() genutzt werden. Diese liefert genau dann als Ergebnis True zurück, wenn die
Zeichenkette mit dem angegebenen Teilstring endet.
In gleicher Weise wie endswith() gibt die Funktion startswith() als Ergebnis True
zurück, wenn die Zeichenkette mit dem angegebenen Teilstring beginnt. Beide Funktionen
liefern andererseits False als Ergebnis.
16
Komplexere Suchmuster sind mit Hilfe von regulären Ausdrücken und den zugehörigen
Funktionen aus dem re-Modul möglich.
Zeichenketten sind unveränderbar. Daher kann der Index-Operator nicht auf der linken
Seite des Zuweisungsoperators = stehen; beispielsweise würde die Eingabe von 'Hallo
Welt'[0:5] = 'Salut' einen TypeError erzeugen. Um eine solche Veränderung vorzu-
nehmen, kann jedoch beispielsweise die speziell für Zeichenketten definierte replace()-
Funktion genutzt werden, und der daraus resultierende String wieder der ursprünglichen
Variable zugewiesen werden:
Komplexere Ersetzungen sind mit Hilfe von regulären Ausdrücken und den zugehörigen
Funktionen aus dem re-Modul möglich.
Python achtet bei der Behandlung von Zeichenketten auf die Groß- und Kleinschreibung.
Sollen also beispielsweise zwei Wörter hinsichtlich nur ihres Inhalts, nicht jedoch hin-
sichtlich der Groß- und Kleinschreibung verglichen werden, so werden üblicherweise beide
zunächst in Kleinbuchstaben umgewandelt. Hierfür kann die Funktion lower() verwendet
werden:
'Hallo'.lower() == 'hallo'
# Ergebnis: True
Die Funktion upper(), wandelt in umgekehrter Weise alle Buchstaben einer Zeichenkette
in Großbuchstaben um. Zwei ähnliche Funktionen sind capitalize(), bei einer Zeichen-
kette nur den ersten Buchstaben als Großbuchstaben und die restlichen als Kleinbuchsta-
ben ausgibt sowie title(), die bei jedem Wort einer Zeichenkette den ersten Buchstaben
als Großbuchstaben und die übrigen als Kleinbuchstaben ausgibt. Mit swapcase() kön-
nen zudem alle Großbuchstaben einer Zeichenkette in Kleinbuchstaben und umgekehrt
umgewandelt werden.
Mittels der Funktionen lstrip() oder rstrip() können Leerzeichen am Anfang oder am
Ende einer Zeichenkette entfernt werden; mittelsstrip() werden Leerzeichen sowohl am
Anfang wie auch am Ende einer Zeichenkette entfernt.
Die Funktion rstrip() wird häufig eingesetzt, um beim Einlesen einer Textdatei alle
Leerzeichen am Ende der einzelnen Zeilen zu entfernen.
17
Mittels der Funktion center() kann eine Zeichenkette umgekehrt über eine bestimm-
te Textbreite zentriert ausgegeben werden. Beispielsweise gibt 'Hallo'.center(20) als
Ergebnis die Zeichenkette ' Hallo ' zurück. Eine derartige Formatierung kann beispiels-
weise für eine tabellarische Ausgabe von Daten nützlich sein.
Mittels der Funktion split() kann eine Zeichenkette in eine Liste von Teilstrings auf-
geteilt werden. Als Argument wird dabei üein Zeichen oder eine Zeichenfolge angegeben,
gemäß der die Aufteilung erfolgen soll. Verwendet man beispielsweise als Trennzeichen
das Leerzeichen ' ', so wird die Zeichenkette in einzelne Wörter aufgeteilt.
# Zeichenkette aufteilen:
Wird die Funktion split() ohne Trennzeichen als Argument aufgerufen, so wird die
Zeichenkette an allen Whitespace-Zeichen aufgetrennt. So kann beispielsweise mit len(
text.split() ) die Anzahl der Wörter in einer Zeichenkette gezählt werden.
# Zeichenkette zusammenfügen:
Umgekehrt kann mittels der Funktion join() eine Liste von Teilstrings zu einer einzigen
Zeichenkette zusammengesetzt werden. Dabei wird zunächst in der Zeichenkette ein Ver-
bindungszeichen (oder eine Folge von Verbindungszeichen) angegeben, als Argument der
join()-Funktion wird dann die Liste der zu verknüpfenden Teilstrings übergeben.
Bisweilen mag man beispielsweise mit print() den Wert einer Variablen als Teil einer
Zeichenkette ausgeben. Zu diesem Zweck können in die Zeichenkette Platzhalter eingebaut
werden, die dann durch die gewünschten Werte ersetzt werden. Dies funktioniert der
„klassischen“ Methode nach (wie etwa in C) so:
var = 5829
18
var_1 = 8913
var_2 = 7824
# Ergebnis: 'Der Wert von var_1 ist 8913, der Wert von var_2 ist 7824.'
var = 5829
var_1 = 8913
var_2 = 7824
In diesem Fall werden die geschweiften Klammern innerhalb der Zeichenkette als Platz-
halter angesehen und durch die als Argumente der Funktion format() angegebenen Va-
riablen ersetzt. Als einzige Besonderheit müssen bei dieser Methode „echte“ geschweifte
Klammern, die als Textsymbole in der Zeichenkette vorkommen sollen, durch {{ bzw. }}
dargestellt werden.
Eine komplette Liste an möglichen Format-Angaben findet sich in der offiziellen Python-
Dokumentation.
Sonstiges:
Eine vollständige Liste an String-Funktionen erhält man, indem man die Funktiondir()
auf einen beliebigen String anwendet, beispielsweisedir(string_1). Nähere Informatio-
nen können dann beispielsweise mittels help(string_1.replace) aufgerufen werden.
Listen und Tupel dienen der Sequenzierung von Objekten beliebigen Datentyps. Sie kön-
nen unterschiedliche Datentypen in beliebiger Reihenfolge beinhalten. Listen werden in
Python durch eckige Klammern, Tupel durch runde Klammern gekennzeichnet; die ein-
zelnen Elemente werden durch jeweils ein Komma-Zeichen voneinander getrennt.
19
Der einzige Unterschied zwischen Listen, die mit [ und ] gekennzeichnet sind, und Tu-
peln, deren Elemente zwischen ( und ) stehen, liegt darin, dass die Inhalte von Listen
3
verändert werden können, während die Inhalte von Tupeln unveränderbar sind. Tupel
können genutzt werden, um die Datensicherheit bestimmter Variablen, die an verschiede-
nen Stellen eines Programms genutzt werden, zu gewährleisten; im allgemeinen werden
jedoch bevorzugt Listen genutzt.
Mittels der Schlüsselwörter in beziehungsweise not in kann geprüft werden, ob ein Ob-
jekt in einer Liste enthalten ist oder nicht:
'a' in liste_1
# Ergebnis: True
liste_1[0]
# Ergebnis: 'a'
liste_1[1]
# Ergebnis: 'b'
liste_1[-2]
# Ergebnis: '2'
liste_1[-1]
# Ergebnis: '3'
Bereiche („Slices“) einer Liste können mit Hilfe des Index-Operators ausgewählt werden,
indem man zwei mit einem Doppelpunkt getrennte Index-Zahlen n1 und n2 angibt; dabei
muss beachtet werden, dass in Python bei Bereichsangaben die obere Grenze nicht im
Bereich eingeschlossen ist:
liste_1[3:5]
# Ergebnis: [1, 2]
Wird bei der Verwendung von Slices die obere und/oder die untere Bereichsangabe weg-
gelassen, so werden die Elemente vom Anfang an beziehungsweise bis zum Ende hin
3 Genau genommen sind bei einem Tupel (oder auch einem frozenset) nur die Referenzen auf die
enthaltenen Ob jekte unveränderlich. Enthält ein Tupel beispielsweise als erstes Argument eine Liste
namens l, so kann dieser mittels l.insert(0, 'Hallo!') ein neues Element hinzugefügt werden. Das
Tupel ändert sich dabei nicht, da die ID der Liste l unverändert bleibt.
20
ausgewählt. Ebenso wie bei Zeichenketten kann zudem ein dritter Parameter angegeben
werden, der festlegt, jedes wie vielte Element ausgewählt werden soll:
liste_1[1:5:2]
# Ergebnis: ['a', 'c', 2]
Ist der Wert des dritten Parameters negativ, so wird die Liste von hinten nach vorne
abgearbeitet.
Mehrdimensionale Listen
Listen können „verschachtelt“ sein, eine Liste kann also weitere Listen als Elemente bein-
halten. Durch eine derartige Struktur könnten beispielsweise die Werte einer Tabelle ge-
speichert werden, die aus mehreren Zeilen besteht, wobei jede Zeile wiederum mehrere
Spalten enthält.
Bei der Indizierung von verschachtelten Listen kann der Index-Operator mehrmals hin-
tereinander angewendet werden:
liste_3[1]
# Ergebnis: ['d','e','f']
Durch die erste Indizierung wird im obigen Beispiel eine Teilliste ausgewählt; auf die-
se Liste als Ergebnis der ersten Indizierung kann erneut der Indexoperator angewendet
werden, um ein darin enthaltenes Element (oder auch einen Bereich) auszuwählen.
Listen-Funktionen
Für Listen existieren Funktionen, die in der Form liste.funktionsname() angewendet
werden können.
Listen verknüpfen
liste_1 = [1, 2, 3]
liste_2 = [4, 5, 6]
liste_1.extend(liste_2)
(continues on next page)
21
(Fortsetzung der vorherigen Seite)
liste_1
# Ergebnis: [1, 2, 3, 4, 5, 6]
Durch die Funktion extend() wird die erste Liste um die Elemente der zweiten Liste
erweitert; die Funktion extend() selbst liefert den Wert None als Ergebnis zurück. Möchte
man eine derartige neue Liste erstellen, ohne dabei die ursprünglichen Listen zu verändern,
kann der +-Operator verwendet werden:
liste_1 = [1, 2, 3]
liste_2 = [4, 5, 6]
liste_1
# Ergebnis: [1, 2, 3]
liste_2
# Ergebnis: [4, 5, 6]
liste_3
# Ergebnis: [1, 2, 3, 4, 5, 6]
Ebenso kann beispielsweise mittels 3 * liste_1 eine Liste erzeugt werden, die aus einer
dreifachen Wiederholung der liste_1 besteht:
liste_4 = 3 * liste_1 ; liste_4
# Ergebnis: [1, 2, 3, 1, 2, 3, 1, 2, 3]
Möchte man eine zweite Liste als eigenes Element zu einer Liste hinzufügen, so kann die
Funktion append() verwendet werden:
liste_1.append(liste_2)
# Ergebnis: [1, 2, 3, [4, 5, 6]]
Listen sortieren
Mittels der Funktion sort() können die Elemente einer Liste in aufsteigender Reihenfolge,
mittels reverse() in absteigender Reihenfolge sortiert werden:
# Liste sortieren:
liste_5.sort()
liste_5
(continues on next page)
22
(Fortsetzung der vorherigen Seite)
# Ergebnis: [-5, 1, 2, 3, 8]
liste_5.reverse()
liste_5
# Ergebnis: [8, 3, 2, 1, -5]
Um zu prüfen, wie häufig ein bestimmtes Element in einer Liste enthalten ist, kann die
Funktion count() angewendet werden:
liste_1.count(3)
# Ergebnis: 1
Soll nur geprüft werden, ob ein Element in einer Liste enthalten ist, so kann auch das
Schlüsselwort in verwendet werden; im obigen Beispiel könnte somit 3 in liste_1 ge-
schrieben werden, um zu prüfen, ob das Element 3 in der Liste vorkommt.
Die Position (des ersten Auftretens) eines Elements innerhalb einer Liste kann mittels der
4
Funktion index() bestimmt werden:
liste_1.index(3)
# Ergebnis: 2
Demnach kann der Wert 3 im obigen Beispiel mittels liste_1[2] aufgerufen werden und
ist somit das dritte Element der Liste. Vor der Verwendung von index() sollte allerdings
mittels if element in liste: stets geprüft werden, ob sich das Element in der Liste
befindet, da ansonsten ein ValueError auftritt.
Mittels insert(indexnummer, element) kann ein neues Element vor der angegebenen
Indexnummer eingefügt werden:
liste_1
# Ergebnis: [1, 2, 'Hallo', 3]
Mittels remove(element) oder pop(indexnummer) können Elemente wieder aus der Liste
entfernt werden:
4 Die Funktionen count() und index() sind die einzigen beiden Listenfunktionen, die auch für die
23
(Fortsetzung der vorherigen Seite)
liste_1
# Ergebnis: [1, 2]
Beim Aufruf der pop()-Funktion wird das aus der Liste entfernte Objekt als Ergebnis
zurückgegeben, was beispielsweise in „Stacks“ durchaus erwünscht ist. Das Löschen eines
Listenbereichs zwischen zwei Indexnummern ist mittels del liste[n1:n2] möglich; auch
bei dieser Bereichsangabe wird die obere Grenze nicht mit eingeschlossen.
Zu beachten ist wiederum, dass remove() einen ValueError auslöst, wenn sich das zu
entfernende Element nicht in der Liste befindet, und pop() einen IndexError auslöst,
wenn die Liste kürzer als die angegebene Indexnummer oder leer ist.
Listen kopieren
Listen können nicht einfach mittels des Zuweisungsoperators kopiert werden. Versucht
man dies, so wird lediglich eine neue Referenz erstellt, die auf die gleiche Liste zeigt und
die Inhalte der ursprünglichen Liste verändern kann:
# Liste erstellen:
liste_1 = [0,1,2,3,4,5]
# Test:
liste_1
# Ergebnis: [1, 1, 2, 3, 4, 5]
Der Grund für dieses scheinbar seltsame Verhalten des Python-Interpreters liegt darin,
dass auf diese Weise Listen direkt verändert werden können, wenn sie als Argumente
an Funktionen übergeben werden. Da dies wesentlich häufiger vorkommt als das „echte“
Kopieren einer Liste, ist es in Python der Standard.
Um eine echte Kopie einer Liste zu erstellen, muss die Funktion copy() auf die ursprüng-
liche Liste angewendet werden:
# Liste erstellen:
liste_1 = [0,1,2,3,4,5]
24
Werden jetzt die Inhalte der zweiten Liste geändert, so bleiben die Inhalte der ersten Liste
bestehen.
List-Comprehensions
Mit Hilfe so genannter List-Comprehensions können aus bestehenden Listen neue Listen
erzeugt werden; dabei können beispielsweise Filter auf die die Elemente der bestehenden
Liste angewendet werden; ebenso ist es möglich, Funktionen auf alle Elemente der beste-
henden Liste anzuwenden und die jeweiligen Ergebnisse in der neuen Liste zu speichern.
Beispiele:
Alle Elemente einer bestehenden Liste sollen quadriert werden:
# Ausgangsliste erstellen:
alte_liste = [1, 2, 3, 4, 5]
neue_liste
# Ergebnis: [1, 4, 9, 16, 25]
In diesem Beispiel wird für jedes Element der bestehenden Liste, das jeweils mit einer
temporären Variablen i bezeichnet wird, der Quadratwert i**2 berechnet und das
Ergebnis als neue Liste gespeichert.
Aus einer bestehenden Liste sollen alle geradzahligen Werte ausgewählt werden:
# Ausgangsliste erstellen:
alte_liste = [1, 2, 3, 4, 5]
neue_liste
# Ergebnis: [2, 4]
In diesem Beispiel werden die Elemente der bestehenden Liste, wiederum kurz mit
i bezeichnet, unverändert in die neue Liste aufgenommen, sofern sie die angegebene
Bedingung i % 2 == 0 erfüllen.
Aus zwei bestehenden Listen sollen alle Elemente ausgewählt werden, die in beiden
Listen enthalten sind:
# Ausgangslisten erstellen:
liste_1 = [1, 2, 3, 4, 5]
liste_1 = [2, 3, 4, 5, 6]
25
(Fortsetzung der vorherigen Seite)
gemeinsame_elemente
# Ergebnis: [2, 3, 4, 5]
# Ausgangslisten erstellen:
liste_1 = [1, 2, 3, 4, 5]
liste_2 = [2, 3, 4, 5, 6]
produkte
# Ergebnis: [2, 6, 12, 20, 30]
In diesem Beispiel wurde mit Hilfe der Funktion range() ein Bereich an ganzen
Zahlen festgelegt, den die Variable i durchlaufen soll. Die Variable i bezeichnet
in diesem Fall also nicht ein konkretes Element einer Liste, sondern vielmehr eine
Indexnummer; mittels dieser Indexnummer kann dann auf die Elemente der Aus-
gangslisten zugegriffen werden.
List Comprehensions ermöglichen es allgemein, neue Listen schnell und gut lesbar zu
erzeugen.
Ein Set bezeichnet in Python eine Menge an Objekten beliebigen Datentyps, wobei jedes
Objekt nur ein einziges Mal in der Menge enthalten sein darf. Sets werden in Python in
geschweifte Klammern gesetzt: Durch Anwendung von Operatoren auf paarweise je zwei
Sets können – entsprechend den Regeln der Mengenlehre – neue Sets gebildet werden.
# Schnittmenge:
26
(Fortsetzung der vorherigen Seite)
# Vereinigungsmenge:
set_1 | set_2
# Ergebnis: {'a', 'b', 'c', 'd', 1, 2, 3, 4}
# Differenzmenge:
set_1 \ set_2
# Ergebnis: {'a', 1}
set_1 ^ set_2
# Ergebnis: {'a', 1, 4, 'd'}
Mengen können unter anderem dazu genutzt werden, um aus einer Liste alle mehrfach
vorkommenden Elemente heraus zu filtern. Hierzu wird etwa folgende Syntax genutzt:
list_with_unique_elements = list(set(any_list))
# Ergebnis: ['a', 'b', 'c', 1, 2, 3]
Mit der add()-Funktion lassen sich Elemente zu einer Menge hinzufügen, beispiels-
weise my_set.add('x').
Mit der discard()-Funktion lassen sich Elemente aus einer Menge entfernen, bei-
spielsweise my_set.discard('x').
Mit der copy()-Funktion kann eine Kopie einer Menge erstellt werden, beispielsweise
my_set2 = my_set_.copy().
Mit der clear()-Funktion können alle Elemente einer Menge gelöscht werden, bei-
spielsweise my_set2.clear().
Neben üblichen Sets können mittels der Funktion frozenset() auch unveränderliche
Listen erzeugt werden.
27
dict – Wörterbücher
In Python existiert ein weiterer Datentyp für Schlüssel-Wert-Paare. Ein solches dict ist
somit aufgebaut wie ein Wörterbuch, das zu jedem Eintrag (Schlüssel) eine passende
Erläuterung (Wert) liefert.
Zur Darstellung von dicts werden in Python geschweifte Klammern verwendet. Als
Schlüssel werden meist strings genutzt, die zugehörigen Werte werden durch einen Dop-
pelpunkt getrennt angegeben. Die einzelnen Schlüssel-Wert-Paare werden – wie die Ele-
mente einer Liste – mit je einem Komma voneinander getrennt aufgelistet.
# Beispiel:
address-book = {
name_1 : adresse_1,
name_2 : adresse_2,
name_3 : adresse_3,
...
}
Anstelle von Zeichenketten können auch Zahlen oder andere unveränderbare Objekte ge-
nutzt werden – beispielsweise Tupel. Veränderbare Objekttypen wie beispielsweise Listen
sind hingegen als Schlüssel nicht erlaubt.
Auf die einzelnen Werte eines dicts kann mittels des Index-Operators zugegriffen werden,
wobei jedoch nicht ein numerischer Wert, sondern der Name eines Schlüssels in den eckigen
Klammern angegeben wird:
address-book[name_1]
# Ergebnis: adresse_1
Mittels der dict-Funktionen keys(), values() und items() lassen sich so genannte
„Views“ eines Wörterbuchs erzeugen. Bei einem View handelt es sich um eine Listen-
Variable, die automatisch aktualisiert wird, wenn das zugehörige dict geändert wird.
Mit key_1 in anydict kann geprüft werden, ob der Schlüssel key_1 im Wörterbuch
anydict vorhanden ist (Ergebnis: True oder False).
Um den zum Schlüssel key_1 gehörigen Wert von anydict auszugeben, kann der Index-
Operator [ ] genutzt werden:
28
anydict[key_1]
# Ergebnis: value_1 oder Error
Ist der Schlüssel nicht vorhanden, wird ein KeyError ausgelöst. Möchte man dies verhin-
dern, so kann man folgenden Code nutzen:
anydict.get(key_1, default=None)
# Ergebnis: value_1 oder None
Mittels der dict-Funktion get() können Dictionaries auch als „Zähler“ genutzt werden:
Soll beispielsweise festgehalten werden, wie häufig einzelne Worte in einem Text vorkom-
men, so legt man zunächst mittels wortanzahl = dict() ein neues dict an; anschließend
kann wortweise geprüft werden, ob dieses Wort bereits als Schlüssel im dict enthalten
ist. Ist dies der Fall, so wird der zugehörige „Counter“-Wert um 1 erhöht, andernfalls wird
ein neuer Schlüssel mit dem Wert 1 angelegt. Ist das zu prüfende Wort in der Variable
wort gespeichert, so genügt für die genannte Aufgabe bereits ein Einzeiler:
# Prüfen, ob Wort bereits im Dict enthalten ist;
# Counter um 1 erhöhen
wortanzahl[wort] = wortanzahl.get(wort, 0) + 1
file – Dateien
Datei-Objekte stellen in Python die Hauptschnittstelle zu externen Dateien auf dem Com-
puter dar. Sie können genutzt werden, um Dateien beliebigen Typs zu lesen oder zu
schreiben.
Datei-Objekte werden erzeugt, indem man die Funktion open() aufruft, und dabei den
Namen der Datei sowie ein Kürzel für den gewünschten Bearbeitungsmodus angibt:
Als Bearbeitungsmodus kann 'r' (lesen), 'w' (schreiben) oder 'rw' (lesen und schrei-
ben) gewählt werden. Sollen binäre Dateien gelesen beziehungsweise geschrieben werden,
muss an das jeweilige Kürzel ein b angehängt werden, beispielsweise bezeichnet 'rb' den
Lesemodus einer binären Datei.
Wird eine Datei im Lesemodus geöffnet, so kann sie beispielsweise mittels der Funktion
read() im Ganzen als ein einziger String eingelesen werden:
Diese Methode ist für größere Dateien nicht empfehlenswert. Besser ist es, mittels der
Funktion readline() eine Datei Zeile für Zeile einzulesen. Bei jedem solchen Aufruf wird
29
die jeweils eingelesene Zeile als Ergebnis zurückgegeben und der „Cursor“ für die aktuelle
Position in der Datei auf die nächste Zeile gesetzt. Mit der Funktion readlines() wird
die Datei zeilenweise in eine Liste von Zeichenketten eingelesen.
Noch einfacher ist ein zeilenweises Einlesen, indem die Datei-Variable selbst als iterierbares
Objekt an eine for -Schleife übergeben wird:
Am Ende eines Lesezugriffs sollte die Datei mittels close(myfile) wieder geschlossen
werden.
Schreiben in Dateien
Anschließend kann mittels der Funktion write() eine (gegebenenfalls auch mehrzeilige)
Zeichenkette in die Datei geschrieben werden:
myfile.write('Hallo Welt!\n')
Mit dieser Variante wird die Datei automatisch geschlossen, auch wenn beim Lesen oder
Schreiben ein Fehler aufgetreten ist.
30
Kontrollstrukturen
Die folgenden Kontrollstrukturen können zur Steuerung eines Programms verwendet wer-
den, wenn einzelne Code-Blöcke nur unter bestimmten Bedingungen oder auch mehrfach
ausgeführt werden sollen. In Python werden dabei keine Klammern zur Markierung von
Code-Blöcken verwendet; stattdessen werden Einrückungen zur Gruppierung und Kennt-
lichmachung einzelner Code-Blöcke genutzt. Üblicherweise wird für jede Einrückungstiefe
ein Tabulator-Zeichen (entspricht vier Leerzeichen) verwendet.
Mit Hilfe von if-Abfragen ist es möglich, Code-Teile nur unter bestimmten Bedingun-
gen ablaufen zu lassen. Ist die if-Bedingung wahr, so wird der anschließende, mit einer
Einrückung hervorgehobene Code ausgeführt.
if bedingung:
Optional können nach einem if-Block mittels elif eine oder mehrere zusätzliche Be-
dingungen formuliert werden, die jedoch nur dann untersucht werden, wenn die erste
if-Bedingung falsch ist. Schließlich kann auch eine else-Bedingung angegeben werden,
die genau dann ausgeführt wird, wenn die vorherige Bedingung (beziehungsweise alle vor-
herigen Bedingungen bei Verwendung eines elif-Blocks) nicht zutreffen.
if bedingung_1:
...
elif bedingung_2:
...
else:
...
Bei der Untersuchung der einzelnen Bedingungen werden die Werte von Variablen häufig
mittels Vergleichsoperatoren überprüft. Mehrere Teilbedingungen können zudem mittels
logischer Operatoren zu einer Gesamtbedingung verknüpft werden:
31
Werden zwei Bedingungen mit and verknüpft, so ist das Ergebnis genau dann wahr,
wenn beide Bedingungen erfüllt sind.
Werden zwei Bedingungen mit or verknüpft, so ist das Ergebnis dann wahr, wenn
mindestens eine der beiden Bedingungen (oder beide zugleich) erfüllt sind.
Der Operator not kehrt den Wahrheitswert einer Bedingung um, eine wahre Bedin-
gung liefert also False als Ergebnis, eine falsche Bedingung True.
Da die logischen Operatoren eine geringer Priorität haben als die Vergleichsoperatoren,
können mehrere Vergleiche auch ohne Klammern mittels and beziehungsweise or verbun-
den werden.
# Beispiel:
Beinhaltet eine Variable 𝑣𝑎𝑟 einen Listentyp, beispielsweise ein Tupel , einen String , ein
Dict oder ein Set, so ergibt if var den Wert False, falls die Länge der Liste gleich Null
ist, und True, falls die jeweilige Liste mindestens ein Element beinhaltet.
Mittels Schleifen kann ein Code-Abschnitt wiederholt ausgeführt werden. Python bietet
hierfür zweierlei Möglichkeiten: Mittels einer while-Schleife wird Code so lange ausge-
führt, solange eine angegebene Bedingung wahr ist; mit einer for-Schleife lassen sich
auch komplexere Schleifentypen erzeugen.
while-Schleifen
while bedingung:
32
Ist die Bedingung wahr, so werden die im unmittelbar folgenden Block stehenden Anwei-
sungen ausgeführt. Vor jedem weiteren Durchlauf wird wieder geprüft, ob die angegebene
Bedingung erfüllt ist; sobald dies nicht der Fall ist, wird die Schleife abgebrochen.
Unmittelbar an den while-Block kann optional auch noch ein else-Block angefügt wer-
den, der genau einmal ausgeführt wird, sobald die while-Bedingung das erste mal den
Wahrheitswert False annimmt. Damit kann beispielsweise eine Programmstruktur fol-
gender Art geschaffen werden:
else:
Der Ablauf einer while kann durch folgende beide Schlüsselwörter im Inneren des Anwei-
sungsblocks beeinflusst werden:
Mittels break wird die Schleife unmittelbar an der jeweiligen Stelle beendet.
while True:
if bedingung:
break
for-Schleifen
33
Ein iterierbares Objekt kann beispielsweise eine Liste, ein Tupel, oder auch ein String
sein. Im einfachsten Fall kann auch mittels der Funktion range() ein iterierbares Objekt
mit bestimmter Länge erzeugt werden:
summe = 0
for i in range(1,10):
summe += i
print(summe)
# Ergebnis: 45
Beim Entwickeln eines Programms kann es passieren, dass eine Kontrollstruktur Funktion
oder Fehlerroutine zunächst nur teilweise implementiert wird. Eine Anweisung ohne Inhalt
würde allerdings einen Syntaxfehler zur Folge haben. Um dies zu vermeiden, kann die
pass-Anweisung eingefügt werden, die keine weitere Bedeutung für das Programm hat.
Beispiel:
var_1 = None
if var_1 is None:
pass
else:
print( "The value of var_1 is %s ." % var_1 )
Die pass-Anweisung stellt somit eine Erleichterung beim Entwickeln von Programmen
dar, da man sich mit ihrer Hilfe zunächst an wichtigeren Programmteilen arbeiten kann.
In fertigen Programmen werden pass-Anweisungen nur selten verwendet.
34
Funktionen
function_code
...
return result
Zum Benennen von Funktionen werden in Python üblicherweise nur kleine Buchstaben
verwendet. Häufig besteht ein Funktionsname aus einem Verb, das die Wirkungsweise der
Funktion beschreibt; liegt jedoch der Zweck einer Funktion nur darin, einen bestimmten
Wert auszugeben, so kann der Funktionsname auch aus einem Substantiv bestehen, das
den jeweiligen Wert beschreibt – beispielsweise wird die Wurzelfunktion meist mit sqrt()
(„square root“) anstelle von calculate_sqrt() bezeichnet. Besteht ein Funktionsname
aus mehreren Wörtern, so werden diese zur besseren Lesbarkeit mittels Unterstrichen
getrennt.
Nach ihrer Definition kann die Funktion dann folgendermaßen aufgerufen werden:
Eine Funktion kann, abhängig von ihrer Definition, beim Aufruf kein, ein oder auch meh-
rere Argumente in der jeweiligen Reihenfolge verlangen. Bei jedem Aufruf wird dann der
Funktions-Code ausgeführt und ein entsprechender Ergebniswert zurück gegeben; ist im
1 Soll eine Funktion mehrere Ergebnisse liefern, so müssen diese als Liste oder Tupel zurückgegeben
werden.
35
Funktionsblock keine return-Anweisung enthalten, wird von der Funktion automatisch
2
der Wert None zurückgegeben.
Optionale Argumente
In Python ist es möglich, bei der Definition von Funktionen optionale Argumente mit
einem Standard-Wert anzugeben. Wird ein solches optionales Argument beim Aufruf der
Funktion nicht explizit angegeben, so wird stattdessen der Standard-Wert genutzt.
Die Funktion kann anschließend wahlweise mit einem oder mit zwei Argumenten aufge-
rufen werden:
my_function(5)
# Ergebnis: (5, 'Test')
my_function(5, 7)
# Ergebnis: (5, 7)
Hat eine Funktion sowohl „normale“ als auch optionale Argumente, so müssen die optio-
nalen Argumente am Ende der Funktion angegeben werden.
Ebenso ist es möglich, einer Funktion eine optionale Liste oder ein optionales Dict für
zusätzliche Argumente anzugeben. Üblicherweise lautet die Syntax dafür:
2 In einer Funktionsdefinition können auch, wenn if-Bedingungen in ihr vorliegen, an mehreren Stel-
len return-Anweisungen auftreten. Sobald eine return-Anweisung erreicht wird, wird die Funktion un-
mittelbar beendet und der jeweilige Ergebniswert zurück gegeben. Steht nur return (ohne expliziten
Soll eine Funktion mehrere Werte als Ergebnis liefern, so müssen diese als Liste oder Tupel an das
36
def any_function(argument_1, argument_2="default value", *args, **kwargs)
pass
Beim Aufruf der Funktion muss argument_1 angegeben werden, die Angabe von
argument_2 ist optional; zusätzlich können weitere unbenannte oder benannte Argumente
angegeben werden, beispielsweise any_function(5,2,7,foo=9). Im obigen Beispiel kön-
nen alle unbenannten Argumente innerhalb der Funktion über die Variable args, alle
benannten über die Variable kwargs aufgerufen werden. Werden beim Funktionsaufruf
keine weiteren Argumente übergeben, so ist args innerhalb der Funktion ein leeres Tupel
und kwargs ein leeres Dict.
Hat man im Quellcode vorab eine Liste an Objekten definiert, die man dann als Argumente
an eine Funktion übergeben möchte, so muss diese bei der Übergabe entpackt werden.
Dies ist mittels des *-Operators möglich:
my_list = [1,3,5,7]
sum_it_up(*my_list)
# Ergebnis: 6
Im obigen Beispiel wurde die Listemy_list bei der Übergabe an die Funktion entpackt;
der Aufruf von sum_it_up(*my_list) ist in diesem Fall also identisch mit sum_it_up(1,
3,5,7). Die ersten beiden Zahlen werden dabei als Argumente für num_1 und num_2
angesehen, die verbleibenden beiden werden innerhalb der Funktion in die Variable nums
3
gespeichert.
Nach dem gleichen Prinzip kann ein Dict mit Schlüsselwort-Wert-Paaren mittels ** ent-
packt an eine Funktion übergeben werden; dabei müssen alle im Dict enthaltenen Schlüs-
selwörter als mögliche Funktionsargumente erlaubt sein.
3 Dass die obige Funktion die Länge der zusätzlichen Zahlenliste zum Ergebnis dazu addiert, soll an
dieser Stelle nur die Funktionalität der optionalen Argumente zeigen. Um alle Elemente dieser Liste zu
summieren, muss zusätzlich das Modul functools geladen werden; in der Beispielaufgabe Quader wird
37
Ist any_object ein veränderliches Objekt, beispielsweise eine Liste, ein Dict oder
ein Set, so kann dieses durch die Funktion direkt verändert werden:
my_list = [1,2,3]
def foo(any_list):
any_list.append(4)
foo(my_list)
print(my_list)
# Ergebnis: [1,2,3,4]
Wird allerdings der übergebenen Referenz x in der Funktion ein neues Objekt zu-
gewiesen, so entspricht dies einer Definition einer neuen Variablen innerhalb der
4
Funktion als Namensraum. Die ursprüngliche Referenz x bleibt in diesem Fall un-
verändert und zeigt nach wie vor auf das ursprüngliche Objekt:
my_list = [1,2,3]
def foo(any_list):
any_list = [1,2,3,4]
foo(my_list)
print(my_list)
# Ergebnis: [1,2,3]
Ist any_object ein unveränderliches Objekt, beispielsweise ein String oder ein Tu-
pel, so wird bei der Übergabe an die Funktion eine Kopie des Objekts erzeugt; das
ursprüngliche Objekt kann somit durch die Funktion nicht verändert werden:
def foo(any_string):
any_string.replace('World', 'Python')
foo(my_string)
print(my_string)
# Ergebnis: 'Hello World!'
Möchte man den obigen Beispielcode so umschreiben, dass nach Aufruf der Funk-
tion die Variable my_string den Wert 'Hello Python!' bekommt, so muss man
folgendermaßen vorgehen:
4 Variablen sind nur innerhalb ihres Namensraums gültig. Ausnahmen sind globale Variablen, die
beispielsweise zu Beginn eines Moduls definiert sind. Eine solche kann dann innerhalb einer Funktion
mittels global var_name als global gekennzeichnet werden, wobei var_name der Name der Variablen ist.
38
my_string = 'Hello World!'
def foo(any_string):
x = any_string.replace('World', 'Python')
return x
my_string = foo(my_string)
print(my_string)
# Ergebnis: 'Hello Python!'
Da Strings nicht verändert werden können, kann eine Veränderung der zugehörigen
Variablen also nur über eine neue Zuweisung erfolgen.
Die Übergabe eines veränderlichen Datentyps, beispielsweise einer Liste, als Argument
an eine Funktion ist zwar performance-technisch günstig, da nur eine neue Referenz auf
die Liste erzeugt werden muss; es können aber unerwartete Fehler auftreten, wenn durch
eine Funktion das übergebene Original der Liste unmittelbar verändert wird. Durch Ver-
wendung von Tupeln anstelle von Listen kann dies auf Kosten von CPU und Memory
ausgeschlossen werden.
Jeder Funktionsblock hat einen eigenen Namensraum, was bedeutet, dass Variablen, die
innerhalb des Funktionsblocks definiert werden, nur im Programm existieren, bis der
Funktionsblock abgeschlossen ist. Derartige Variablen, die nur innerhalb der Funktion
„sichtbar“ sind, werden „lokale“ Variablen genannt.
Einer lokalen Variablen kann dabei der gleiche Name zugewiesen werden wie einer Va-
riablen, die außerhalb des Funktionsblocks definiert wurden; sie „überdeckt“ in diesem
Fall die nicht-lokale Variable: Der Interpreter sucht primär im lokalen Namensraum nach
dem Variablennamen und erst sekundär im nicht-lokalen Namensraum, wenn keine lokale
Variable mit dem angegebenen Namen existiert. und nur.
Wird einer lokalen Variablen ein Wert zugewiesen, so ändert sich also der Wert einer
nichtlokalen Variablen nicht:
# Funktion aufrufen:
myfunc()
# Ergebnis: 1
(continues on next page)
39
(Fortsetzung der vorherigen Seite)
x
# Ergebnis: 0
Soll der Wert einer nicht-lokalen Variablen durch die Funktion verändert werden, so kann
diese bei einem veränderlichen Datentyp als Argument an die Funktion übergeben werden.
Variablen mit nicht veränderlichem Datentyp können, wie im letzten Abschnitt beschrie-
ben, eine Veränderung erreicht werden, nur durch eine Zuweisung des Rückgabewerts der
Funktion geändert werden.
Eine weitere prinzipielle Möglichkeit, die jedoch möglichst vermieden werden sollte, ist
es, mittels des Schlüsselworts global einen Variablennamen primär im nicht-lokalen Na-
mensraum zu suchen:
# Funktion aufrufen:
myfunc()
# Ergebnis: 1
x
# Ergebnis: 1
Das Schlüsselwort global hat nur Auswirkungen innerhalb der Funktion, eine Variable
kann also nicht von außerhalb der Funktion als „global“ gekennzeichnet und als solche
der Funktion aufgezwungen werden. Dennoch kann die Verwendung von global zu uner-
warteten Seiteneffekten führen, wenn eine Variable prinzipiell von mehreren Stellen aus
verändert werden kann, da in diesem Fall nicht immer auf den ersten Blick einwandfrei
feststellbar ist, von wo aus die Variable verändert wurde.
Lambda-Ausdrücke
40
übergeben werden sollen, und einem Doppelpunkt. Hinter diesem Doppelpunkt wird in
der gleichen Zeile die Wirkungsweise des Lambda-Ausdrucks definiert, beispielsweise:
add(5,3)
# Ergebnis: 8
Bei der Definition eines Lambda-Ausdrucks entfällt also das Schlüsselwort def, und die
Argumente werden unmittelbar hinter dem Schlüsselwort lambda ohne runde Klammern
angegeben.
Ein Nachteil von Lambda-Ausdrücken ist, dass in ihnen keine Schleifen, Kontrollstruk-
5
turen oder komplexeren Anweisungsblöcke vorkommen dürfen. Ein wichtiger Vorteil ist
hingegen, dass Lambda-Ausdrücke keinen expliziten Namen haben müssen. Beispielsweise
kann der gesamte Lambda-Ausdruck, wenn man ihn in runde Klammern setzt, unmittel-
bar wie eine Funktion aufgerufen werden:
print(result)
# Ergebnis: 8
# Beispiel 1:
my_list = [1,2,3,4,5,6,7,8,9]
list(even_numbers)
# Ergebnis: [2,4,6,8]
# Beispiel 2:
my_list = [1,2,3,4]
list(even_numbers)
# Ergebnis: [2,4,6,8]
Ebenso kann ein Lambda-Ausdruck als Kriterium für die sort()-Funktion genutzt wer-
den, um beispielsweise eine Liste von Zweier-Tupeln nach den ersten Elementen der Tupel
zu sortieren:
5 Eine Bedingte Wertzuweisung in der Form lambda x: a if condition else b ist allerdings er-
laubt.
41
my_list = [(3, 1), (1, 2), (11, -3), (5, 10)]
my_list.sort(key=lambda x: x[0])
print(my_list)
# Ergebnis: [(1, 2), (3, 1), (5, 10), (11, -3)]
Auch bei der Entwicklung von graphischen Oberflächen sind Lambda-Ausdrücke nützlich,
um einzelnen Maus-Events oder Tastenkombinationen bestimmte Funktionen zuzuweisen.
Builtin-Funktionen
Neben der bereits erwähnten print()-Funktion, die zur Anzeige von Texten und Va-
riablen auf dem Bildschirm dient, gibt es in Python weitere grundsätzlich verfügbare
Funktionen, so genannte „Builtin“-Funktionen; Diese Funktionen sind ohne das Importie-
ren weiterer Module unmittelbar verfügbar. Eine Übersicht über diese Funktionen findet
sich im Anhang: Standard-Funktionen .
42
Klassen und Objektorientierung
Eine neue Klasse wird in Python mit dem Schlüsselwort class, gefolgt vom Klassennamen
und einem Doppelpunkt eingeleitet. Alle darauf folgenden Definitionen von Eigenschaften
und Funktionen, die zur Klasse gehören, werden um eine Tabulatorweite (üblicherweise 4
Leerzeichen) eingerückt.
Ebenso wichtig wie der Begriff einer Klasse ist der Begriff der Instanz einer Klasse. Wäh-
rend beispielsweise die Klasse „Wecker“ einen Objekttyp eines meist unhöflich Lärm er-
zeugenden Gerätes darstellt, so ist ein einzelner neben einem Bett stehender Wecker ein
konkreter Vertreter dieser Klasse. Eine solche Instanz hat, zumindest in der Programmie-
rung, stets alle in der Klasse definierten Eigenschaften und Funktionen, allerdings mit
möglicher unterschiedlicher Ausprägung (beispielsweise Farbe oder Klingelton).
class AlarmClock():
"""
Just a simple Class example.
"""
Arguments:
43
(Fortsetzung der vorherigen Seite)
def show_color(self):
return self.color
def ring(self):
return self.sound + "!!!"
Im obigen Beispiel wurde zunächst die Klasse AlarmClock definiert und als. erstes mit
einem Docstring versehen, der eine kurze Beschreibung der Klasse liefert.
In der Funktion __init__() wird anschließend festgelegt, wie eine neue Instanz der Klasse
erzeugt wird. Die angegebenen Argumente werden dabei als Eigenschaften der Instanz,
die in Python mit self bezeichnet wird, gespeichert. Nach der Initialisierung stehen im
obigen Beispiel dem neuen Objekt dann die beiden weiteren angegebenen Funktionen
show_color() und ring() bereit, die als Ausgabe der jeweiligen Objektvariablen dienen.
Die Methode __init__() wird automatisch aufgerufen, wenn man den Namen der Klasse
als Funktion aufruft. Eine neue Instanz einer Klasse lässt sich im Fall des obigen Beispiels
also folgendermaßen erzeugen:
# Initialisierung:
my_alarm_clock = AlarmClock("green", "Ring Ring Ring")
# Objekttyp testen:
type(my_alarm_clock)
# Ergebnis: __main__.AlarmClock
# Funktionen testen:
my_alarm_clock.show_color()
# Ergebnis: 'green'
my_alarm_clock.ring()
# Ergebnis: 'Ring Ring Ring!!!'
Mittels type(objektname) kann allgemein angezeigt werden, zu welcher Klasse ein belie-
biges Python-Objekt gehört; ebenso kann mit isinstance(objektname, klassenname)
geprüft werden, ob ein Objekt eine Instanz der angegebenen Klasse ist.
Möchte man eine konkrete Instanz wieder löschen, so ist dies allgemein mittels
del(name_der_instanz) möglich, im obigen Fall also mittels del(my_alarm_clock). Ge-
nau genommen wird die Instanz allerdings nur dann gelöscht, wenn die letzte Referenz auf
die Instanz gelöscht wird. Sind beispielsweise mittels alarm_clock_1 = alarm_clock_2
= AlarmClock("blue", "Ring!") zwei Referenzen auf die gleiche Instanz erzeugt wor-
den, so wird mittels del(alarm_clock_1) nur die erste Referenz gelöscht; die Instanz
selbst bleibt weiter bestehen, da die Variable alarm_clock_2 immer noch darauf verweist.
Beim Löschen der letzten Referenz auf wird automatisch Pythons „Garbage Collector“ ak-
tiv und übernimmt die Aufräumarbeiten, indem die entsprechende __del__()-Methode
44
aufgerufen wird; ebenso wird der benötigte Platz im Arbeitsspeicher dadurch automatisch
wieder freigegeben.
Sollen bei der Löschung einer Instanz weitere Aufgaben abgearbeitet werden, so können
diese in einer optionalen Funktion __del__() innerhalb der Klasse festgelegt werden.
Klassen dienen allgemein dazu, die Attribute und Methoden (kurz: „Member“) einzelner
Objekte festzulegen. Bei der Festlegung der Attribute und Methoden wird jeweils das
Schlüsselwort self genutzt, das auf die jeweilige Instanz einer Klasse verweist.
Attribute eines Objekts werden mittels self.attributname = wert festgelegt; dies er-
folgt üblicherweise bereits bei der Initialisierung. Anschließend kann auf die so definier-
ten Attribute innerhalb der Klasse mittels self.attributname und außerhalb mittels
instanzname.attributname zugegriffen werden.
Methoden eines Objekts werden ebenso wie Funktionen definiert, mit der einzigen Be-
sonderheit, dass als erstes Argument stets self angegeben wird. Innerhalb der Klas-
se können so definierte Methoden mittels self.methodenname() und außerhalb mittels
instanzname.methodenname() aufgerufen werden.
In manchen Fällen möchte man vermeiden, dass die Attribute eines Objekts durch andere
Objekte manipuliert werden können; ebenso sind manche Methoden nur für den „internen“
Gebrauch innerhalb einer Klasse geeignet. In Python gibt es für diesen Zweck sowohl
geschützte („protected“) als auch private („private“) Attribute und Methoden:
Geschützte Member (Attribute und Methoden) werden durch einen einfach Unter-
strich vor dem jeweiligen Namen gekennzeichnet. Auf derartige Attribute oder Me-
thoden kann weiterhin von einer anderen Stelle aus sowohl lesend als auch schreibend
zugegriffen werden; es ist vielmehr eine Konvention zwischen Python-Entwicklern,
dass auf derartige Member nicht direkt zugegriffen werden sollte.
Private Member werden durch einen doppelten Unterstrich vor dem jeweiligen Na-
men gekennzeichnet. Auf derartige Attribute kann außerhalb der Klasse weder lesend
noch schreibend zugegriffen werden.
Attribute sollten beispielsweise dann als geschützt oder privat gekennzeichnet werden,
wenn sie nur bestimmte Werte annehmen sollen. In diesem Fall werden zusätzlich so ge-
nannte „Getter“ und „Setter“-Methoden definiert, deren Aufgabe es ist, nach einer Prüfung
auf Korrektheit den Wert des entsprechenden Attributs auszugeben oder ihm einen neuen
Wert zuzuweisen.
45
class MyClass:
def __init__(self):
self._myattr = None
def get_myattr(self):
return self._myattr
self._myattr = value
Mittels der property()-Funktion wird die Setter- und Getter-Methode eines geschützten
oder privaten Attributs dem gleichen, nicht-geschützten Attributnamen zugewiesen. Von
außerhalb der Klasse ist dieses gezielte Handling also nicht sichtbar, das entsprechen-
de Attribut erscheint von außen also wie ein gewöhnliches Attribut. Dieses Prinzip der
Kapselung von Aufgaben ist typisch für objektorientierte Programmierung: Wichtig ist
es, die Aufgabe eines Objekts klar zu definieren sowie seine „Schnittstellen“, also seine
von außerhalb zugänglichen Attribute und Methoden, festzulegen. Solange das Objekt als
einzelner Baustein seine Aufgabe damit erfüllt, braucht man sich als Entwickler um die
Interna dieses Bausteins nicht weiter Gedanken zu machen.
Statische Member
Neben Attributen und Methoden, die jede einzelne Instanz einer Klasse an sich bereit-
stellt, können innerhalb einer Klasse auch Attribute und/oder Methoden definiert werden,
die für alle Instanzen der Klasse gleichermaßen gelten. Derartige Klassenmember werden
„statisch“ genannt.
Statische Attribute lassen sich erzeugen, indem innerhalb der Klasse (üblicherweise gleich
zu Beginn des Klassen-Blocks) die gewünschten Attribute wie normale Variablen gesetzt
werden, also ohne vorangestelltes self und außerhalb einer Methoden-Definition. Der
Zugriff auf statische Attribute kann dann (sowohl lesend als auch schreibend) wahlweise
mittels Klassenname.attributname oder mittels Instanzname.attributname erfolgen:
class MyClass:
myattr = 42
pass
46
(Fortsetzung der vorherigen Seite)
MyClass.myattr
# Ergebnis: 42
MyClass().myattr
# Ergebnis: 42
Statische Methoden werden ebenso wie gewöhnliche Methoden definiert, außer dass bei der
Definition das self als erstes Argument weggelassen wird; stattdessen wird die Methode
anschließend mittels der Funktion staticmethod() zur statische Methode deklariert:
class MyClass:
def mymethod():
print("Hello!")
mymethod = staticmethod(mymethod)
MyClass.mymethod()
# Ergebnis: Hello!
MyClass().mymethod()
# Ergebnis: Hello!
Statische Attribute und Methoden können auch dann genutzt werden, wenn (noch) keine
Instanz der Klasse existiert.
„Magic“ Member
Als „Magic Member“ werden private Attribute und Funktionen von Klassen bezeichnet,
die es beispielsweise ermöglichen, einzelne Instanzen der Klassen mittels Operatoren mit-
einander in Relation zu setzen oder Builtin-Funktionen auf die einzelnen Instanzen anzu-
wenden. Die Bezeichnung „magisch“ stammt daher, dass diese Methoden und Attribute
selten direkt mit ihrem Namen angesprochen werden, aber dafür oft implizit genutzt wer-
den – wie beispielsweise die __init__() oder __del__()-Funktionen als Konstruktor-
und Destruktor-Methoden einzelner Instanzen. Beispielsweise wird anstelle MyClass.
__init__() wird üblicherweise MyClass() geschrieben, um eine neue Instanz einer Klasse
zu erzeugen; bei letzterer Variante wird die __init__()-Funktion vom Python-Interpreter
implizit aufgerufen.
Mittels der Methode __str()__ wird eine für Menschen gut lesbare Zeichenkette
definiert, die beim Aufruf von str(MyClass) als Objektbeschreibung ausgegeben
werden soll.
47
Die Methode __repr() wird so definiert, dass sie Python-Code als Ergebnis zurück-
gibt, bei dessen Ausführung eine neue Instanz der jeweiligen Klasse erzeugt wird.
Die Methode __call__() bewirkt, sofern sie definiert ist, dass eine Instanz einer
Klasse – ebenso wie eine Funktion – aufgerufen werden kann.
Mit dem Attribut __dict__ wird als dict aufgelistet, welche Attribute und zugehö-
rigen Werte die jeweilige Instanz der Klasse aktuell beinhaltet.
Durch das (statische) Attribut __slots__ kann mittels einer Liste festgelegt wer-
den, welche Attributnamen die Instanzen einer Klasse haben. Wird versucht, mit-
telsdel(instanzname.attributname) ein Attribut einer Instanz zu löschen, des-
sen Name in der__slots__-Liste enthalten ist, so schlägt das Löschen mit einem
AttributeError fehl. Umgekehrt wird auch dann ein AttributeError ausgelöst,
wenn man versucht, ein neues Attribut für die Instanz festzulegen, dessen Name
nicht in der __slots__-Liste enthalten ist.
Mit der Methode __getattr__() wird definiert, wie sich die Klasse zu verhalten
hat, wenn ein angegebenes Attribut abgefragt wird, aber nicht existiert. Wahlwei-
se kann ein Standard-Wert zurückgegeben werden, üblicherweise wird jedoch ein
AttributeError ausgelöst.
Mit der Methode __setattr__() wird eine Routine angegeben, die aufgerufen
wird, wenn ein Attribut neu erstellt oder verändert wird. Dafür wird zunächst der
Name des Attributs und als zweites Argument der zuzuweisende Wert angegeben.
Insbesondere kann mit dieser Methode kontrolliert werden, dass keine
unerwünschten Attribute vergeben werden können.
Bei der Verwendung von __setattr__() ist zu beachten, dass die Wertzuweisung
mittels self.__dict__['attributname'] = wert erfolgen muss, da ansonsten
eine Endlos-Schleife erzeugt würde.
Mit __delattr__() wird als Methode festgelegt, wie sich eine Instanz beim Aufruf
von del(instanzname.attributname) verhalten soll.
Folgende Member sind für den Vergleich zweier Objekte vorgesehen:
Mit den Methoden __eq__() („equal“) und __ne__() („not equal“) kann fest-
gelegt werden, nach welchen Kriterien zwei Instanzen verglichen werden sol-
48
len, wenn instanz_1 == instanz_2 beziehungsweise instanz_1 != instanz_2
aufgerufen wird. Diese Operator-Kurzschreibweise wird intern in instanz_1.
__eq__(instanz_2) übersetzt, es wird also die Equal-Methode des ersten Objekts
aufgerufen.
Mit den Methoden __gt__() („greater than“) und __ge__() („greater equal“) kann
festgelegt werden, nach welchen Kriterien sich zwei Instanzen verglichen werden
sollen, wenn instanz_1 > instanz_2 instanz_1 >= instanz_2
beziehungsweise
aufgerufen wird. Entsprechend kann mit __lt__() („less than“) und __le__() („less
equal“) kann festgelegt werden, nach welchen Kriterien sich zwei Objekte verglichen
werden, wenn instanz_1 < instanz_2 beziehungsweise instanz_1 <= instanz_2
aufgerufen wird.
Mit der Methode __hash__() wird ein zu der angegebenen Instanz gehörender Hash-
Wert ausgegeben, der die Instanz als Objekt eindeutig identifiziert.
Mit den Methoden __pos__() __neg__() kann festgelegt werden, welche Er-
und
gebnisse die unären Operatoren +instanz beziehungsweise -instanz liefern sollen;
zusätzlich kann mit der Methode __abs__() (Absolut-Betrag) festgelegt werden,
welches Ergebnis ein Aufruf von abs(instanz) liefern soll. Ebenso wird durch die
Methoden __round__() (Rundung) bestimmt, welches Ergebnis beim Aufruf von
round(instanz) bzw. round(instanz, num) zu erwarten ist.
Mit den Methoden __add__(), __sub__(), __mul__() und __truediv__() wird
festgelegt, welches Ergebnis sich bei der Verknüpfung zweier Instanzen mit den
vier Grundrechenarten ergeben soll, also instanz_1 + instanz_2, instanz_1 -
instanz_2, usw. Zusätzlich wird durch die Methode __pow__() (Potenzrechnung)
festgelegt, welches Ergebnis instanz_1 ** instanz__2 liefern soll.
49
er Instanzen mit den vier Grundrechenarten ergeben soll, also instanz_1 +=
instanz_2, instanz_1 -= instanz_2, usw. Zusätzlich wird durch die Metho-
de __ipow__() (Potenzrechnung) festgelegt, welches Ergebnis instanz_1 **=
instanz__2 liefern soll.
Mit der Methode __ifloordiv__() wird die Bedeutung von instanz_1 //=
instanz_2 instanz_1 dabei derjenige Wert
festgelegt; bei normalen Zahlen wird
zugewiesen, der sich bei der Auswertung von instanz_1 // instanz_2 ergibt. In
gleicher Weise wird durch die Methode __imod__() (Modulo-Rechnung) die Bedeu-
tung von instanz_1 %= instanz_2 festgelegt; hierbei erhält instanz_1 als Wert
das Ergebnis von instanz_1 % instanz_2.
Die Methode __len__() wird aufgerufen, wenn mittels len(instanz) die Länge
eines Containers geprüft werden soll.
Folgende Member sind für die Verwendung des Objekts innerhalb von with -Konstrukten
vorgesehen:
Mit der Methode __enter__() werden Anweisungen definiert, die einmalig ausge-
führt werden sollen, wenn eine Instanz der Klasse in eine with -Umgebung geladen
wird.
Mit der Methode __exit__() werden Anweisungen definiert, die einmalig ausge-
führt werden sollen, wenn eine with -Umgebung um eine Instanz der Klasse wieder
verlassen wird.
Mit Hilfe der „Magic Members“ können also neue Klassen von Objekten definiert werden,
deren Verhalten dem von bestehenden Klassen (Zahlen, Listen, usw.) ähnelt. Wird einem
Operator, beispielsweise dem Plus-Operators +, mittels der Funktion __add__() eine neue,
auf den Objekttyp passendere Bedeutung zugewiesen, so spricht man auch von „Operator-
Überladung“.
Objekte zeichnen sich also weniger durch ihre Bezeichnung, sondern vielmehr durch ihre
Eigenschaften und Methoden aus. Dieses Konzept wird bisweilen auch als „Duck Typing“
bezeichnet:
„Wenn ich einen Vogel sehe, der wie eine Ente läuft, wie eine Ente schwimmt
und wie eine Ente schnattert, dann nenne ich diesen Vogel eine Ente.“
—James Riley
50
Kann eine Funktion umgekehrt auf verschiedene Objekt-Typen angewendet werden, so
nennt man sie polymorph. Beispielsweise kann die Builtin-Funktion sum() auf beliebige
listen-artige Objekttypen angewendet werden, sofern für diese eine __add__()-Funktion
definiert ist. Durch Polymorphismus als Spracheigenschaft wird einmal geschriebener Code
oftmals auch an einer anderen Stelle verwendbar.
Vererbung
Mit dem Begriff „Vererbung“ wird ein in der Objekt-orientierten Programmierung sehr
wichtiges Konzept bezeichnet, das es ermöglicht, bei der Definition von fein spezifizierten
Objekte auf allgemeinere Basis-Klassen zurückzugreifen; die Basis-Klasse „vererbt“ dabei
ihre Attribute und Methoden an die abgeleitete Sub-Klasse, wobei in dieser weitere Ei-
genschaften hinzukommen oder die geerbten Eigenschaften angepasst werden können. Aus
mathematischer Sicht ist die Basis-Klasse eine echte Teilmenge der daraus abgeleiteten
Klasse, da diese alle Eigenschaften der ursprünglichen Klasse (und gegebenenfalls noch
weitere) enthält.
Um die Eigenschaften einer Basis-Klasse in einer neuen Klasse zu übernehmen, muss diese
bei der Klassendefinition in runden Klammern angegeben werden:
class SubClass(MyClass):
pass
Bis auf diese Besonderheit werden alle Attribute und Methoden in einer abgeleiteten
Klasse ebenso definiert wie in einer Klasse, die keine Basis-Klasse aufweist.
In Python ist es prinzipiell möglich, dass eine Klasse auch mehrere Basis-Klassen aufweist;
in diesem Fall werden die einzelnen Klassennamen bei der Definition der neuen Klasse
durch Kommata getrennt angegeben. Die links stehende Klasse hat dabei beim Vererben
der Eigenschaften die höchste Priorität, gleichnamige Attribute oder Methoden werden
durch die weiteren Basis-Klassen also nicht überschrieben, sondern nur ergänzt. Da durch
Mehrfach-Vererbungen allerdings keine eindeutige Baumstruktur mehr vorliegt, also nicht
mehr auf den ersten Blick erkennbar ist, aus welcher Klasse die abgeleiteten Attribute und
Methoden ursprünglich stammen, sollte Mehrfach-Vererbung nur in Ausnahmefällen und
mit Vorsicht eingesetzt werden.
Dekoratoren
Der wohl wichtigste Dekorator ist @property : Mit Hilfe dieses Dekorators kann eine get-
Methode zu einem „Attribut“ gemacht werden, dessen Wert nicht statisch in einer Varia-
blen abgelegt ist, sondern dynamisch mittels der dekorierten get-Methode abgefragt wird.
Die grundlegende Funktionsweise ist folgende:
51
# Beispiel-Klasse definieren:
class C(object):
Anhand des obigen Beispiels kann man gut erkennen, dass in der Beispiel-Klasse C neben
der als nur zur internen Verwendung vorgesehenen Variablen _counter auch noch ein
zweites Attribug counter definiert wird, und zwar explizit als Aufruf von property().
Wird viac = C() eine neue Instanz der Klasse erzeugt, so wird mittels c.counter die
get_counter()-Funktion aufgerufen. Die für einen Methoden-Aufruf typischen runden
Klammern entfallen also, von außen hat es den Anschein, als würde auf ein gewöhnli-
ches Attribut zugegriffen. Intern hingegen wird die _counter-Variable, die womöglich an
anderen Stellen innerhalb der Klasse verändert wird, ausgegeben.
class C(object):
_counter = 0
@property
def get_counter(self):
return self._counter
Die Zeile @property wird dabei „Dekorator“ genannt. Diese Kurzschreibweise hat den
gleichen Effekt wie das obige, explizite Wrapping der zugehörigen Methode.
. . . to be continued . . . .. TODO
Generatoren sind Objekte, die über eine __next__()-Funktion verfügen, also bei jedem
Aufruf von next(generator_object) einen neuen Rückgabewert liefern. Man kann sich
einen Generator also vorstellen wie eine Funktion, die mit jedem Aufruf das nächste
Element einer Liste zurückgibt. Kann der Generator keinen weiteren Rückgabewert liefern,
wird ein StopIteration-Error ausgelöst.
Der Vorteil von Generatoren gegenüber Listen liegt darin, dass auch bei sehr großen
Datenmengen kein großer Speicherbedarf nötig ist, da immer nur das jeweils aktuell zu-
rückgegebene Objekt im Speicher existiert. Beispielsweise handelt es sich auch bei File -
52
Objekten um Generatoren, die beim Aufruf von next(fileobject) jeweils die nächste
Zeile der geöffneten ausgeben. Auf diese Weise kann der Inhalt einer (beliebig) großen
Datei beispielsweise mittels einer for-Schleife abgearbeitet werden, ohne dass der Inhalt
der Datei auf einmal eingelesen und als Liste gespeichert werden muss.
Generatoren werden mit einer Syntax erzeugt, die der von List Comprehensions sehr ähn-
lich ist; es wird lediglich runde Klammern anstelle der eckigen Klammern zur Begrenzung
des Ausdrucks verwendet:
# List Comprehension:
mylist
# Ergebnis: [1, 4, 9, 16, 25, 36, 49, 64, 81]
# Generator:
next(mygen)
# Ergebnis: 1
next(mygen)
# Ergebnis: 4
# ...
next(mygen2)
# Ergebnis: 81
next(mygen2)
# Ergebnis: 256
Python kann diese Art von verschachtelten Generatoren sehr schnell auswerten, so dass
Generatoren allgemein sehr gut für die Auswertung großer Datenströme geeignet sind. Zu
beachten ist lediglich, dass der Generator bei jedem Aufruf – ähnlich wie eine Funktion –
einen Rückgabewert liefert, der von sich aus nicht im Speicher verbleibt, sondern entweder
unmittelbar weiter verarbeitet oder manuell gespeichert werden muss.
53
Module und Pakete
Module
Module bestehen, ebenso wie Python-Skript, aus Quellcode-Dateien mit der Endung .py.
Prinzipiell kann somit jedes Python-Skript als eigenständiges Python-Modul angesehen
werden, es existieren allerdings auch Module, die nur nur aus Hilfsfunktionen bestehen.
In der Praxis werden Module allerdings in erster Linie verwendet, um den Quellcode eines
umfangreicheren Software-Projekts leichter zu organisieren und übersichtlich zu halten.
Eine grobe Regel besagt, dass ein Modul nur so umfangreich sein sollte, dass sich seine
Inhalte und sein Verwendungszweck mit ein bis zwei Sätzen zusammenfassen lassen sollten.
Jedes Modul stellt einen eigenen Namensraum für Variablen dar, so dass gleichnamige
Funktionen, die in unterschiedlichen Modulen definiert sind, keine Konflikte verursachen.
import modulname
# Beispiel:
import antigravity
import this
Das zu importierende Modul muss sich hierbei im Python-Pfad befinden, also entweder
global installiert oder im aktuellen Verzeichnis enthalten sein. Andernfalls ist eine Anpas-
sung der Variablen sys.path nötig.
Nach dem Importieren eines Moduls können die im Modul definierten Klassen , Funktionen
und Variablen mit folgender Syntax aufgerufen werden:
modulname.Klassenname
modulname.variablenname
modulname.funktionsname()
54
Um bei längeren Modulnamen Schreibarbeit sparen zu können, ist beim Importieren eines
Moduls auch eine abkürzende Syntax möglich:
# Beispiel:
import math as m
Anschließend kann das Kürzel als Synonym für den Modulnamen verwendet werden, bei-
spielsweise m.pi anstelle von math.pi.
Eine weitere Vereinfachung ist möglich, wenn man nur einzelne Klassen oder Funktionen
eines Moduls importieren möchte. Hierfür ist folgende Syntax möglich:
Dabei können auch mehrere Klassen- oder Funktionsnamen jeweils durch ein Komma
getrennt angegeben werden. Die so importieren Klassen bzw. Funktionen können dann
direkt aufgerufen werden, als wären sie in der aktuellen Datei definiert.
Es ist auch möglich, mittels from modulname import * alle Klassen und Funktionen eines
Moduls zu importieren. Hiervon ist allerdings (zumindest in Skript-Dateien) dringend
abzuraten, da es dadurch unter Umständen schwer nachvollziehbar ist, aus welchem Modul
eine später benutzte Funktion stammt. Zudem können Namenskonflikte entstehen, wenn
mehrere Module gleichnamige Funktionen bereitstellen.
Hilfe zu Modulen
Mittels help(modulname) kann wiederum eine Hilfeseite zu dem jeweiligen Modul ein-
geblendet werden, in der üblicherweise eine Beschreibung des Moduls angezeigt wird
und eine Auflistung der im Modul definierten Funktionen. Bei den Standard-Modulen
wird zudem ein Link zur entsprechenden Seite der offiziellen Python-Dokumentation
https://docs.python.org/3/ angegeben.
Die __name__-Variable
Jedes Modul bekommt, wenn es importiert wird, automatisch eine __name__-Variable zu-
gewiesen, die den Namen des Moduls angibt. Wird allerdings eine Python-Datei unmittel-
bar als Skript mit dem Interpreter aufgerufen, so bekommt dieses „Modul“ als __name__-
Variable den Wert __main__ zugewiesen.
Wenn Python-Module importiert werden, dann werden sie einmalig vom Interpreter aus-
geführt, das heißt alle darin aufgelisteten Definitionen und Funktionsaufrufe werden zum
Zeitpunkt des Importierens (einmalig) aufgerufen. Möchte man einige Funktionen in ei-
ner Python-Datei nur dann ausführen, wenn die Datei als Skript aufgerufen wird, nicht
jedoch, wenn sie als Modul in ein anderes Programm eingebunden wird, so kann man dies
mittels folgender Anweisung erreichen:
55
if __name__ == __main__:
Dies ist insbesondere für Mini-Programme nützlich, die wahlweise als selbstständiges Pro-
gramm aufgerufen, oder in ein anderes Programm eingebettet werden können.
Ist ein Modul einmal importiert, so wird jede weitere import-Anweisung des gleichen
Moduls vom Python-Interpreter ignoriert. Dies ist in den meisten Fällen von Vorteil, denn
auch wenn beispielsweise mehrere Module eines Programms das Modul sys importieren,
so wird dieses nur einmal geladen.
Schreibt man allerdings selbst aktiv an einem Programmteil und möchte die Änderungen
in einer laufenden Interpreter-Sitzung (z.B. Ipython) übernehmen, so müsste der Interpre-
ter nach jeder Änderung geschlossen und neu gestartet werden. Abhilfe schafft in diesem
Fall die im Modul imp definierte Funktion reload(), die ein erneutes Laden eines Moduls
ermöglicht:
import imp
import modulname
Dies funktioniert auch, wenn ein Modul mit einer Abkürzung importiert wurde, beispiels-
weise import modulname as m; in diesem Fall kann das Modul mittels imp.reload(m)
neu geladen werden.
Pakete
Ein Programm kann somit in mehrere Teilpakete untergliedert werden, die wiederum
mittels derimport-Anweisung wie Module geladen werden können. Enthält beispielsweise
ein Paket pac die Module a und b, so können diese mittels import pac geladen und
mittels pac.a beziehungsweise pac.b benutzt werden; zur Trennung des Paket- und des
Modulnamens wird also wiederum ein Punkt verwendet. Ebenso kann mittels import
pac.a nur das Modul a aus dem Paket pac geladen werden.
Die import-Syntax für Pakete lautet somit allgemein:
56
(Fortsetzung der vorherigen Seite)
# Alternativ:
from paket import modulname
Wird ein Modul mittels from paket import modulname importiert, so kann es ohne An-
gabe des Paketnamens benutzt werden; beispielsweise können darin definierte Funktionen
mittels modulname.funktionsname() aufgerufen werden. Eine weitere Verschachtelung
von Paketen in Unterpakete ist ebenfalls möglich.
Mit . wird dabei der aktuelle Ordner bezeichnet. Ebenso kann ein Modul mittels from ..
import modulname aus dem übergeordneten Verzeichnis und mittels from ... import
modulname aus dem nochmals übergeordneten Verzeichnis importiert werden. Dies ist
allerdings nicht in der Hauptdatei möglich, mit welcher der Python-Interpreter aufgerufen
wurde und die intern lediglich den Namen __main__ zugewiesen bekommt: Diese darf nur
absolute Pfadangaben für Imports enthalten.
Möchte man selbst ein Paket zu einer Python-Anwendung erstellen, so ist etwa folgender
1
Aufbau empfehlenswert:
My_Project/
|
|- docs
| |- conf.py
| |- index.rst
| |- installation.rst
| |- modules.rst
| |- quickstart.rst
| |- reference.rst
|
|- my_project/
(continues on next page)
1 Siehe auch Open Sourcing a Python Pro ject the Right Way und Filesystem structure of a Python
57
(Fortsetzung der vorherigen Seite)
| |- main.py
| |- ...
|
|- tests/
| |- test_main.py
| |- ...
|
|- CHANGES.rst
|- LICENSE
|- README.rst
|- requirements.txt
|- setup.py
|- TODO.rst
Das Projekt-Verzeichnis sollte den gleichen Namen wie die spätere Anwendung haben, al-
lerdings mit einem Großbuchstaben beginnen, um Verwechslungen mit dem gleichnamigen
Paket-Verzeichnis zu vermeiden. Das Projekt-Verzeichnis sollte neben dem eigentlichen
Projekt-Paket zumindest noch die Ordner docs, undtest umfassen, in denen eine Do-
kumentation des Projekts und zum Programm passende Tests enthalten sind; zusätzlich
kann das Projekt einen lib-Ordner mit möglichen C-Erweiterungen enthalten. In man-
chen Projekten werden zudem ausführbare Programm-Dateien (meist ohne die Endung
.py) in einem weiteren Ordner bin abgelegt; hat ein Programm allerdings nur eine einzelne
aufrufbare Datei, so kann diese auch im Projekt-Hauptverzeichnis abgelegt werden.
Das Paket setuptools aus der Python-Standardbibliothek stellt einige Funktionen bereit,
die für das Installieren von Python-Paketen hilfreich sind. Dazu wird üblicherweise im
Projekt eine Datei setup.py angelegt, die unter anderem eine Programmbeschreibung,
den Namen und die Emailadresse des Autors, Informationen zur Programmversion und
zu benötigten Fremdpaketen enthält. Zudem können mit der Funktion find_packages()
aus dem setuptools-Paket die im Projektverzeichnis enthaltenen Pakete automatisch
gefunden und bei Bedarf installiert werden.
try:
from setuptools import setup, find_packages
(continues on next page)
58
(Fortsetzung der vorherigen Seite)
except ImportError:
import ez_setup
ez_setup.use_setuptools()
from setuptools import setup, find_packages
import os
import my_project
my_project_path = os.path.abspath(os.path.dirname(__file__))
long_description =
"""
Eine ausführliche Beschreibung des Programms.
"""
setup(
name='my_project',
version=my_project.__version__,
url='http://github.com/my_account/my_project/',
license='GPLv3',
author='Vorname Nachname',
author_email='name@adresse.de',
install_requires=[
'Flask>=0.10.1',
'SQLAlchemy==0.8.2',
],
tests_require=['nose'],
packages=find_packages(exclude=['tests']),
description='Eine kurze Beschreibung.',
long_description = long_description,
platforms='any',
keywords = "different tags here",
classifiers = [
'Programming Language :: Python',
'Development Status :: 4 - Beta',
'Natural Language :: English',
'Intended Audience :: Developers',
'Operating System :: Linux',
'Topic :: Software Development :: Libraries :: Application Frameworks',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
],
59
Fehler und Ausnahmen
Fehler gehören für Programmierer zum Alltag: Komplexe Computerprogramme laufen nur
selten fehlerfrei, schon gar nicht in der Entwicklungsphase. Die möglichen auftretenden
Fehler lassen sich allgemein in drei Arten unterteilen:
Enthält ein Programm Syntax-Fehler, so werden diese beim Versuch eines Pro-
grammaufrufs angezeigt, und das Programm startet nicht.
Die zwei geläufigsten Syntax-Checker für Python-Code sind pylint und pyflakes;
zudem gibt es einen „Style“-Checker namens pep8, der prüft, ob die offiziellen Emp-
fehlung für das Aussehen von Python-Code eingehalten werden (beispielsweise keine
Zeilen mit mehr als 80 Zeichen auftreten). Diese zusätzlichen Werkzeuge können fol-
gendermaßen installiert werden:
Gibt man nach der Installation pylint skriptname.py ein, so werden einer-
seits darin möglicherweise enthaltene Syntax-Fehler aufgelistet, andererseits werden
Empfehlungen zur Verbesserung der Code-Syntax gegeben – unter anderem wird
darauf hingewiesen, wenn eine Funktionsdefinition keinen Docstring enthält.
Laufzeit-Fehler treten auf, wenn ein Programm versucht, eine ungültige Operation
durchzuführen, beispielsweise eine Division durch Null oder ein Öffnen einer nicht
vorhandenen Datei. Laufzeit-Fehler treten also erst auf, wenn das Programm (in der
Regel ohne Fehlermeldung) bereits läuft.
60
Laufzeit-Fehler können in Python allgemein mittels try-except -Konstrukten abge-
fangen werden.
Logische Fehler treten auf, wenn ein Programm zwar (anscheinend) fehlerfrei funk-
tioniert, jedoch andere Ergebnisse liefert als erwartet. Bei solchen Fehlern liegt das
Problem also an einem Denkfehler des Programmierers.
Logische Fehler sind oft schwer zu finden; am besten hilft hierbei ein Debugger,
mit dem man den Programmablauf Schritt für Schritt nachvollziehen kann (siehe
Abschnitt pdb – der Python-Debugger ).
Tritt in einem Python-Programm ein Fehler auf, der nicht von einer entsprechenden Rou-
tine abgefangen wird, so wird das Progarmm beendet und ein so genannter „Traceback“
angezeigt. Bei dieser Art von Fehlermeldung, die man von unten nach oben lesen sollte,
wird als logische Aufruf-Struktur angezeigt, welche Funktion beziehungsweise Stelle im
Programm den Fehler verursacht hat; für diese Stelle wird explizit der Dateiname und die
Zeilennummer angegeben.
Mit dem Schlüsselwort try wird eine Ausnahmebehandlung eingeleitet: Läuft der try-
Block nicht fehlerfrei durch, so kann der Fehler mittels einer except-Anweisung abge-
fangen werden; in diesem Fall werden alle Anweisungen des jeweiligen except-Blocks
ausgeführt.
Optional kann neben einer try und einer beziehungsweise mehreren except-Anweisungen
auch eine else-Anweisung angegeben werden, die genau dann ausgeführt wird, wenn die
try-Anweisung keinen Fehler ausgelöst hat:
try:
# Diese Anweisung kann einen FileNotFoundError auslösen:
file = open('/tmp/any_file.txt')
except FileNotFoundError:
print("Datei nicht gefunden!")
except IOError:
print("Datei nicht lesbar!")
else:
# Datei einlesen, wenn kein Fehler augetreten ist:
data = file.read()
finally:
# Diese Anweisung in jedem Fall ausführen:
file.close()
Zusätzlich zu try und except kann man optional auch einen finally-Block angeben;
Code, der innerhalb von diesem Block steht, wird auf alle Fälle am Ende der Ausnah-
61
mebehandlung ausgeführt, egal ob der try-Block fehlerfrei ausgeführt wurde oder eine
Exception aufgetreten ist.
Das with-Statement
# Datei-Objekt erzeugen:
myfile = open("filename.txt", "r")
try:
# Datei einlesen und Inhalt auf dem Bildschirm ausgeben:
content = myfile.read()
print(content)
finally:
# Dateiobjekt schließen:
f.close()
Diese verhältnismäßig häufig vorkommende Routine kann kürzer und eleganter auch mit-
tels eines with-Statements geschrieben werden:
Hierbei versucht Python ebenfalls, den with-Block ebenso wie einen try-Block auszu-
führen. Die Methode ist allerdings wesentlich „objekt-orientierter“: Durch die im with-
Statement angegebene Anweisung wird eine Instanz eines Objekts erzeugt, in dem obigen
Beispiel ein file-Objekt; innerhalb des with-Blocks kann auf dieses Objekt mittels des
hinter dem Schlüsselwort as angegebenen Bezeichners zugegriffen werden.
In der Klasse des durch das with-Statement erzeugten Objekts sollten die beiden Me-
thoden __enter__() und __exit()__ definiert sein, welche Anweisungen enthalten, die
unmittelbar zu Beginn beziehungsweise am Ende des with-Blocks aufgerufen werden. Bei-
spielsweise besitzen file-Objekte eine __exit__()-Methode, in denen die jeweilige Datei
wieder geschlossen wird.
Mit dem Schlüsselwort raise kann eine Ausnahme an der jeweiligen Stelle im Code selbst
ausgelöst werden. Dies ist unter anderem nützlich, um bei der Interpretation einer Benut-
zereingabe fehlerhafte Eingaben frühzeitig abzufangen.
Wird von einem Benutzer beispielsweise anstelle einer Zahl ein Buchstabe eingegeben, so
kann dies beim Aufruf der weiterverarbeitenden Funktion mit großer Wahrscheinlichkeit
62
zu Fehlern führen. Da der Fehler jedoch bei der Eingabe entstanden ist, sollte auch an
dieser Stelle die entsprechende Fehlermeldung (ein ValueError) ausgelöst werden.
63
Debugging, Logging und Testing
Im folgenden Abschnitt werden Methoden vorgestellt, die beim Auffinden, Beheben und
Vermeiden von Fehlern hilfreich sind.
Ein Debugger wird verwendet, um ein fehlerhaftes Programm Schritt für Schritt ablaufen
zu lassen, um den Fehler schnell ausfindig machen zu können; er kann ebenso verwen-
det werden, um die Funktionsweise ein unbekanntes Programms leichter nachvollziehen
zu können, indem man sieht, welche Funktionen im Laufe des Programms nacheinander
aufgerufen werden.
pdb3 scriptfile.py
Nach dem Aufruf erscheint der pdb-Eingabeprompt (Pdb). Hier können unter anderem
folgende Anweisungen eingegeben werden:
p und pp:
Mit p wird der angegebene Ausdruck ausgewertet und das Ergebnis angezeigt; bei-
spielsweise gibt p variablenname den Wert der angegebenen Variablen zum aktu-
ellen Zeitpunkt im Programm an. Mit pp wird das Ergebnis in „pretty print“-Form
ausgegeben.
64
return (oder kurz: r):
Mit return wird das Programm bis zum Ende der aktuellen Funktion weiter aus-
geführt.
– Wird break mit einer ganzzahligen Nummer als Argument aufgerufen, so wird
ein Breakpoint an dieser Stelle im Quellcode des Programms gesetzt; das heißt,
der Debugger hält an, wenn diese Stelle erreicht wird.
– Wird break mit einem Funktionsnamen als Argument aufgerufen, so wird ein
Breakpoint bei dieser Funktion gesetzt, das heißt, der Debugger hält jedes mal
an, wenn diese Funktion aufgerufen wird.
Zusätzlich lassen sich im Debugger auch Python-Statements ausführen; hierzu muss die
jeweilige Eingabe-Zeile lediglich mit einem Ausrufezeichen (!) begonnen werden.
Eine weitere, oftmals sogar bessere Nutzungs-Variante ist es, den Debugger nicht direkt
aufzurufen, sondern ihn erst ab einer bestimmten Stelle aus dem Programm heraus zu
starten. Hierzu kann man folgendermaßen vorgehen:
import pdb
65
Nach dem Importieren des pdb-Moduls kann man an einer beliebigen Stelle, auch inner-
halb einer Funktion, mit pdb.set_trace() den Debugger starten. Auch bei dieser Be-
nutzungsweise erscheint der pdb-Eingabeprompt, wo wiederum die obigen Anweisungen
genutzt werden können; das Debuggen beginnt dann allerdings erst an der „spannenden“
Stelle.
Logdateien können ebenso wie ein Debugger genutzt werden, um Fehler in einem Pro-
gramm zu finden. Hierzu nutzt man im Quellcode des Programms Anweisungen, die große
Ähnlichkeit mit simplen print()-Anweisungen haben. Die Ausgabe wird allerdings üb-
licherweise nicht auf dem Bildschirm, sondern mit einer Standard-Formatierung in eine
1
Logdatei geschrieben.
In Python kann ein Logging einfach mit Hilfe des logging <htt-
ps://docs.python.org/3/library/logging.html>-Moduls umgesetzt werden. Beispiels-
weise kann man ein Logging in einer interaktiven Interpreter-Sitzung folgendermaßen
aktivieren:
import logging
# Basis-Einstellungen festlegen:
logging.basicConfig(level=logging.INFO)
# Logger-Nachricht erzeugen:
logger.info("Los geht's!")
# Ergebnis:INFO:__main__:Los geht's!
Über die Angabe des Log-Levels wird festgelegt, wie dringlich eine Nachricht ist. Im
logging-Modul sind dabei folgende Werte festgelegt:
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0
1 Gegenüber einfachen print()-Anweisungen, die ebenfalls beispielsweise zur Ausgabe von Variablen-
werten zu einem bestimmten Zeitpunkt genutzt werden können, haben Logger als Vorteil, nach dem
‚Debuggen‘ zwingend wieder aus dem Code entfernt werden zu müssen; zudem stehen für Logger ver-
schiedene Dringlichkeits-Stufen zur Verfügung, so dass die Ausgabe der Logging-Nachrichten nur dann
erfolgt, wenn die jeweilige Stufe (mittels einer Einstellung) aktiviert wird.
66
immer dann, wenn ihr Dringlichkeitswert über dem in der Basis-Einstellung festgelegten
Level liegt.
import logging
import modul1
import modul2
# Basis-Einstellungen festlegen:
logging.basicConfig(filename='log.txt',
format='%(levelname)s : %(message)s ',
level=logging.DEBUG)
# Logger-Nachricht erzeugen:
logger.info("Los geht's!")
In diesem Fall wurden bei der Festlegung der Basis-Einstellungen zusätzlich eine Logdatei
und eine Standardfomat angegeben. Wird das Programm aufgerufen, so wird hierdurch
in der angegebenen Logdatei folgender Eintrag erzeugt:
Wird die obige Konfiguration in der Basis-Datei eines Programms vorgenommen, das als
Ankerpunkt für weitere Module dient, so genügt innerhalb dieser Module bereits die An-
weisung import logging zu Beginn der jeweiligen Datei, um innerhalb des Moduls eben-
falls mittels logger.info(nachricht) Einträge in die Logdatei des Basis-Programms
schreiben zu können.
Da mittels Lognachrichten auch, ebenso wie mit print() , Variablenwerte ausgegeben wer-
den können, kann die Verwendung von Logdateien in vielen Fällen sogar einen Debugger
ersetzen.
>>> power(5, 3)
125
(continues on next page)
67
(Fortsetzung der vorherigen Seite)
Beim Schreiben von Doctests werden Zeilen, die normalerweise direkt im Python-
Interpreter eingegeben werden, mit >>> eingeleitet; in der darauffolgenden Zeile wird dann
eingegeben, welches Ergebnis beim Aufruf der vorherigen Zeile erwartet wird. Stimmt beim
Durchlaufen der Doctests ein tatsächliches Ergebnis nicht mit dem erwarteten Ergebnis
überein, so schlägt der jeweilige Test fehl, und eine entsprechende Fehlermeldung wird
angezeigt.
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=1)
Werden diese Zeilen an das Ende des zu testenden Moduls geschrieben, so kann man an-
schließend python3 modulname.py aufrufen, um die Tests zu aktivieren; wird Das Modul
hingegen nur importiert, so wird der Code-Abschnitt ignoriert.
Alternativ können Doctests auch direkt durch den Aufruf des Interpreters aktiviert wrden:
Hierbei wird mittels der Interpreter-Option -m das doctest-Modul geladen, zudem werden
mittels der Option -v („verbose“) ausführliche Ausgabe-Informationen angezeigt.
Doctests eignen sich nur für verhältnismäßig einfache Tests, in denen nur eine geringe
Anzahl von Tests je Funktion durchgeführt werden und auch keine umfangreiche Vorbe-
reitung der Einsatz-Umgebung notwendig ist; dies würde die Docstrings allzu umfangreich
und die Code-Dateien damit zu unübersichtlich machen. Eine bessere Alternative bieten
an dieser Stelle Unit-Tests.
Beim Schreiben von Unit-Tests mit Hilfe des unittest-Pakets wird zu jedem Modul
modulname.py ein entsprechendes Test-Modul test_modulname.py, mit dessen Hilfe wel-
che die im Hauptmodul enthaltenen Funktionen getestet werden können. Alle diese so
genannten Unit Tests sollten voneinander unabhängig sein.
68
Da manche Funktionen oder Module im normalen Betrieb eine bestimmte Umgebung
benötigen, beispielsweise einen aktiven Webserver, eine Datenbank, oder eine geöffnete
Beispieldatei, können innerhalb der Test-Module mittels der Funktionen setup() und
teardown() solche Umgebungen bereitgesetellt werden; diese beiden Funktionen werden
bei jedem Test aufgerufen und erzeugen beziehungsweise bereinigen die benötigte Umge-
bung.
Ein Test-Funktionen einer Unitt-Test-Datei beginnen jeweils mit mit test_, gefolgt vom
Namen der zu testenden Funktion. Um Klassen zu testen, werden in der Unit-Test-Datei
ebenfalls Klassen definiert, deren Namen sich aus der Zeichenkette Test_ und und den
eigentlichen Klassennamen zusammensetzt. Diese Klassen haben unittest.TestCase als
Basisklasse.
import unittest
from modulname import KlassenName
class Test_KlassenName(unittest.TestCase):
def setUp(self):
pass
def test_funktionsname1(self):
...
def test_funktionsname2(self):
...
...
def tearDown(self):
pass
In Python gibt es, je nach Art der Hypothese, mehrere mögliche assert-Anweisungen:
Mit assertEqual(funktion(), ergebnis) kann geprüft werden, ob der Rückga-
bewert der angegebenen Funktion mit dem erwarteten Ergebnis übereinstimmt.
...
69
if __name__ == '__main__':
unittest.main()
Gibt man dann python3 test_modulname.py ein, so werden durch die Funktion
unittest.main() alle in der Datei enthaltenen Tests durchlaufen. Als Ergebnis wird
dann angezeigt, wieviele Tests erfolgreich absolviert wurden und an welcher Stelle gege-
benenfalls Fehler aufgetreten sind.
Das Programm nose vereinfacht das Aufrufen von Unit-Tests, da es automatisch alle
Test-Funktionen aufruft, die es im aktuellen Verzeichnis mitsamt aller Unterverzeichnisse
findet; eine Test-Funktion muss dazu lediglich in ihrem Funktionsnamen die Zeichenkette
test enthalten.
Um Tests mittels nose zu finden und zu aktivieren, genügt es in einer Shell in das Test-
Verzeichnis zu wechseln und folgende Zeile einzugeben:
nosetest3
Bei Verwendung von nose erübrigt sich also das Schreiben von Test-Suits. Wird
nosetests3 --pdb aufgerufen, so wird automatisch der Python-Debugger pdb gestartet,
falls ein Fehler auftritt.
70
Design Patterns
An dieser Stelle sollen einige hilfreiche Entwurfsmuster („Design Patterns“) und ihre Imple-
1
mentierungen in Python3 vorgestellt werden. Derartige Entwicklungsmuster kann man als
„Entwicklungshilfen“ ansehen, da sie bewährte Code-Strukturen für bestimmte Problem-
Typen bieten.bestimmte Problem-Typen bieten.
Erzeugungsmuster
Factory
Als „Factories“ werden Hilfsobjekte bezeichnet, deren Aufgabe es ist, die Erzeugung eines
Objekts von seiner Verwendung zu trennen. Man unterscheidet im Allgemeinen zwischen
der „Factory Method“ und der „Factory Class“ als zwei verschiedenen Möglichkeiten, dieses
Prinzip zu implementieren.
Factory Method
Bei einer „Factory Method“ wird ein neues Objekt durch den Aufruf einer Funktion erzeugt
und von dieser als Ergebnis zurückgegeben. Die erzeugende Funktion erstellt das neue
Objekt dabei in Abhängigkeit vom Kontext. Beispielsweise kann nach diesem Prinzip eine
Funktion read_file() ein Datei-Reader-Objekt in Abhängigkeit vom Dateityp bzw. der
Datei-Endung des angegebenen Pfads generieren:
# Factory-Method-Beispiel
class CSV_Reader():
1 Eine allgemeine, nicht Python-spezifische Übersicht über Design Patterns gibt es unter anderem auf
Wikipedia.
71
(Fortsetzung der vorherigen Seite)
def file_reader(path):
if path.endswith(".csv"):
return CSV_READER(path)
else:
return None
csv_reader = file_reader('test.csv')
Soll durch eine Factory Method eine direkte Instanziierung einer Klasse verhindert werden,
so kann die Definition dieser Klasse auch innerhalb der Funktionsdefinition erfolgen.
Factory Class
Bei einer „Factory Class“ wird eine Factory-Methode (oder mehrere davon) zu einer Klas-
se zusammengefasst. Bei Verwendung dieses Patterns kann man beispielsweise eine Klasse
names ConnectionCreator mit einer Methode build_connection(connection_type) er-
stellen, die je nach angegebenem Protokoll-Typ eine SSH- oder FTP-Verbindung zu einem
Webserver aufbaut. Strukturell könnte der Code dann folgendermaßen aussehen:
# Factory-Class-Beispiel
# Connection-Klassen:
class SSH_Connection():
class FTP_Connection():
# Factory-Klasse:
class ConnectionCreator():
if connection_type == "HTML":
return HTML_Connection(path)
(continues on next page)
72
(Fortsetzung der vorherigen Seite)
else:
return None
Nach dem gleichen Prinzip denkbar wäre beispielsweise auch eine DatabaseConnection-
Klasse, die eine Verbindung zu einer bestehenden Datenbank herstellen kann, oder gege-
benenfalls auch eine neue Datenbank anlegen kann.
Abstract Factory
In der Programmierung werden bisweilen „abstrakte“ Klassen definiert. Diese geben zwar
bereits strukturelle Prinzipien vor, es können allerdings noch keine Instanzen einer solchen
Klasse erzeugt werden, da konkrete Ausprägungen noch nicht festgelegt sind. Beispiels-
weise könnte eine abstrakte Klasse ein „Kraftfahrzeug“ sein, das ganz allgemein Methoden
wie „Motor starten“ oder „Bremse betätigen“ bereit stellt. Jeder reelle Kraftfahrzeug-Typ,
der auf dieser Klasse via Vererbung aufbaut, implementiert diese Funktionen, allerdings
konkretisiert auf die konkrete Ausprägung.
Bei Verwendung einer „Abstract Factory“ wird entsprechend ein Factory-Typ mit struk-
turellen Prinzipien vorgegeben, aus dem wiederum konkrete Factory-Klassen (mittels
2
Vererbung) hervorgehen können. Dieses Pattern kann beispielsweise für ein Computer-
Strategiespiel wie 0.A.D genutzt werden, so dass „Gebäude-Typ“ je nach Kultur und Ent-
wicklungsstufe zwar ähnliche, aber nicht komplett identische Objekte generieren kann.
Builder
Das „Builder“-Pattern kann verwendet werden, wenn ein Objekt schrittweise aus einzelnen
Komponenten zusammengestellt werden muss. Die einzelnen Komponenten werden dabei
durch Factory-Methoden einer (oder mehrerer) „Builder“-Klassen erzeugt. Die Builder-
Methoden werden wiederum von einem „Director“-Objekt in der gewünschten Reihenfolge
aufgerufen.
Das gewünschte Objekt als Ganzes wird also über den Direktor in Auftrag gegeben, der
die Anfrage an den passenden Builder weiter reicht. Ist das Objekt erstellt, kann der
Director es wiederum beim Builder abholen und als Ergebnis zurückgeben. Während die
einzelnen Builder wiederum „Factories“ darstellen, ist der Director ein steuerndes Element,
das kontext-bezogen den relevanten Builder auswählt und gewissermaßen „nach Rezept“
nacheinander dessen Methoden aktiviert.
2 Konkrete Factories können konkrete Objekte generieren, abstrakte Faktories hingegen nicht. Zu den
konkreten objekten können zwar separat abstrakte Klassen definiert werden, eine abstrakte Factory kann
allerdings nicht einmal diese generieren, da sie selbst eine abstrakte Klasse darstellt: Eine Abstract Factory
kann nicht instanziiert werden, sie gibt also nur den strukturellen Aufbau einer konkreten Factory vor.
73
Prototype
Mittels eines „Prototyps“ kann ein neues Objekt erstellt werden, indem ein bestehendes
Objekt als Startpunkt verwendet wird. Um einen Prototypen zu erzeugen, muss also
zunächst eine exakte Kopie eines bestehenden Objekts erzeugt werden.
In Python ist dies einfach mittels der Funktion deepcopy() aus dem Paket copy der
Standard-Library möglich.
Singleton
Als Singleton bezeichnet man ein Objekt, das innerhalb eines laufenden Programms nur
in einer Ausprägung („Instanz“) existieren darf; beispielsweise ist bei jedem Betriebsys-
tem mit grafischer Oberfläche genau ein Window-Manager in Betrieb. Zugleich muss das
Singleton-Objekt unter Umständen für viele Stellen zugriffsbereit sein.
Singletons stellen also eine Art von klar definierten „Access Points“ dar, auf die von mehre-
ren Clienten aus zugegriffen werden kann. Ein solches Objekt könnte zwar prinzipiell auch
mittels einer globalen Variable initiiert werden, jedoch könnten dabei immer noch mehrere
Instanzen des Objekts existieren – man hätte dann zwar das gleiche, aber nicht das selbe
Objekt. Zudem soll die Klasse des Grundobjekts durch die Erstellung von Unterklassen
erweiterbar sein.
Singleton-Klasse
class Singleton(object):
def __new__(cls):
if not hasattr(cls, 'instance'):
cls.instance = super().__new__(cls)
return cls.instance
Wird ein solches Objekt initiiert, so wird es nur dann eine neue Instanz des Objekts
erzeugt, falls noch keine solche existiert; andernfalls gibt die Initiierung die bereits exis-
tierende Instanz als Ergebnis zurück. Auf diese Weise kann man von beliebiger Stelle aus
auf das Singleton zugreifen, indem man eine neue Instanz des Singletons erzeugt:
Jedes Objekt, das ein Singleton darstellen soll, kann damit der obigen Implementierung
als Unterklasse eines Singletons definiert werden:
74
class Any_Singleton_Object(Singleton):
"""
A Class for a Singleton Object.
"""
Bei der Initiierung eines solchen Objekts wird aufgrund der geerbten __new__()-Funktion
nur dann ein neues Objekt (mit allen „Standardeinstellungen“) erstellt, falls ein solches
noch nicht existiert. Ansonsten wird dieses mit all seinen Methoden und Attributen ge-
nutzt.
Singleton-Module
Die Initiierung eines Objekts ist stets mit etwas Rechenaufwand verbunden. Soll auf ein
Singleton häufig und möglichst schnell zugegriffen werden und ist keine Aufgliederung des
Singletons in mehrere mögliche Unterklassen nötig, so kann anstatt der oben beschrie-
benen Klasse auch ein Singleton-Modul erzeugt werden. Dieses Modul, das den Namen
des Singletons (in Kleinbuchstaben) als Dateinamen (mit Endung .py) trägt, bekommt
„Methoden“ als Funktionen und „Attribute“ als Variablen auf Modulebene zugewiesen –
d.h. in diesem Modul werden keine Klassen angelegt.
Da Module nach erstmaligem Importieren durch import modulname stets nur in Form
einer Referenz genutzt werden, kann auf die gewünschten Singleton-Methoden unmittelbar
mittels modul.funktionsname() und die gewünschten Attribute mittels modul.variable
zugegriffen werden.
Strukturmuster
Adapter
Composite
Facade
Ein Facade-Pattern kann genutzt werden, um einem Benutzer ein einfaches, intuitiv nutz-
bares Interface zu bieten, so dass sich dieser nicht mit den Schnittstellen der einzelnen
Klassen eines Programms auseinander setzen muss. In einer solchen „Fassade“ eines Pro-
gramms sollen also keine neuen Funktionen hinzu kommen, es soll vielmehr der Zugriff
auf die eigentlichen Programm-Funktionen erleichtert werden.
75
Model-View-Controller
Das Prinzip „Model-View-Controller“ soll dabei helfen, die eigentliche Logik des Pro-
gramms (das „Modell“) von der Datenausgabe (dem „View“) zu trennen.
Er soll die Eingabe des Benutzers, die ebenfalls in der View-Ebene erfolgt, entge-
gennehmen und an das Modell weiterleiten.
Er soll, nachdem die Eingabe in der Modell-Ebene verarbeitet wurde, die resultie-
rende Ausgabe wieder an die View-Ebene weiterleiten.
Der Controller wirkt wie ein „Kleber“ zwischen der Modell- und der View-Schicht; man
sagt entsprechend, der Kontroller solle „dünn“ sein, also nur die für die Vermittlung
absolut nötigen Funktionen beinhalten.
Die Modell-Ebene hingegen soll „schlau“ sein, an dieser Stelle sollte also die eigentliche
Programm-Logik liegen.
Die View-Ebene wiederum soll „dumm“ sein, also nur die zur Entgegennahme des Inputs
und zur Darstellung der Ausgabe nötigen Funktionen (und keine weitere Logik)
beinhalten; beispielsweise sollte aus der View-Ebene heraus kein Zugriff auf eine
Datenbank erfolgen.
Der Vorteil dieses Entwicklungs-Musters liegt darin, dass das eigentliche Programm von
der Benutzeroberfläche abstrahiert wird. Etliche Linux-Programme, aber beispielsweise
auch den Python-Interpreter Ipython , gibt es dadurch sowohl als text-basierte Anwendun-
gen für die Shell wie auch als Variante mit einer eigenen graphischen Bedienoberfläche.
Verhaltensmuster
Memento
Memento (Wikipedia, de.)
Observer
Das Observer-Muster besteht darin, dass ein bestimmtes Objekt als „Subjekt“ deklariert
wird, dass von anderen Objekten „beobachtet“ wird. Das Subjekt verwaltet dabei eine Lis-
te aller Objekte, die es beobachten. Ändert sich eine bestimmte Eigenschaft des Subjekts,
dann benachrichtigt es darüber alle Beobachter-Objekte, indem es eine deren Methoden
aufruft.
76
Visitor
. . . to be continued . . .
Links
77
Scientific Python
Unter dem Überbegriff „Scientific Python“ werden in Python einige Pakete zusammenge-
fasst, die speziell für wissenschaftliches Arbeiten entwickelt wurden.
import math as m
Das math-Modul enthält unter anderem folgende Funktionen, die jeweils auf einzelne
Zahlenwerte angewendet werden können:
78
Zudem sind im math-Modul die Konstanten m.pi und m.e für die Kreiszahl 𝜋 ≈ 3, 14
beziehungsweise die Eulersche Zahl 𝑒 ≈ 2, 71 vordefiniert.
Neben dem math-Modul existieren weiter für mathematische Zwecke nützliche Module,
beispielsweise cmath für das Rechnen mit komplexen Zahlen oder functools für das
Anwenden von Operatoren und/oder Funktionen auf eine ganze Liste von Zahlen. Im
folgenden werden einige Anwendungsbeispiele vorgestellt, die sich an den Aufgaben zur
Arithmetik orientieren.
Primfaktor-Zerlegung
Um die Primfaktoren einer ganzen Zahl 𝑛 > 0 zu bestimmen, kann man folgende Funktion
nutzen (Quelle: StackOverflow):
def prim(n):
'''Calculates all prime factors of the given integer.'''
pfactors = []
limit = int(sqrt(n)) + 1
check = 2
num = n
if n == 1:
return [1]
if num > 1:
pfactors.append(num)
return pfactors
Die Grund-Idee von diesem Algorithmus liegt darin, dass eine Zahl keinen Primzahl-
Faktor haben kann, der größer ist als die Quadratwurzel dieser Zahl. Für
√ 𝑛 = 100 ist
beispielsweise 100 = 10 der größtmögliche Faktor, der eine Primzahl sein könnte.
Andere Produkte mit größeren Faktoren 100 = 50·2 lassen sich zwar ebenfalls bilden,
enthalten dann allerdings stets einen Faktor, der kleiner als die Quadrat-Wurzel der
Original-Zahl ist.
Die einzelnen möglichen Primfaktoren lassen sich finden, indem man nacheinander
die Faktoren 2, 3 . . . in aufsteigender Reihenfolge durchprobiert. Um eine mögli-
che Mehrfachheit einzelner Faktoren nicht außer Acht zu lassen, muss bei jedem
gefundenen Faktor geprüft werden, ob sich die Original-Zahl gegebenenfalls auch
mehrfach durch diesen dividieren lässt.
79
Ist ein Faktor gefunden, so kann man die Original-Zahl durch diesen dividieren und
den Algorithmus erneut mit dem resultierenden Divisions-Rest fortsetzen.
Die gefundenen Faktoren sind tatsächlich allesamt Primzahlen: Jeder andere Faktor ließe
sich selbst als Produkt jeweils kleinerer Primzahlen darstellen. Die Teilbarkeit durch diese
Zahlen wurde im Lauf des Algorithmus allerdings bereits geprüft; der jeweilige Divisions-
rest, mit dem der Algorithmus fortfährt, enthält diese Faktoren nicht mehr.
Mittels der obigen Funktion kann nun die Primzahl einer Zahl oder eines Zahlenbereichs
folgendermaßen berechnet werden:
Beim Rechnen mit rationalen Zahlen, insbesondere beim Kürzen eines Bruchterms oder
beim Multiplizieren zweier Brüche, ist es nützlich, den größten gemeinsamen Teiler zweier
Zahlen zu finden. Hierzu wird bis heute ein Algorithmus verwendet, den bereits Euklid in
der Antike entdeckt hat:
Hat man zwei Zahlen 𝑎 und 𝑏 mit 𝑎 > 𝑏, so ist der größte gemeinsame Teiler von
𝑎 und 𝑏 identisch mit dem größten gemeinsamen Teiler von (𝑎 − 𝑏) und 𝑏. Man
kann also wiederholt immer wieder die kleinere Zahl von der größeren abziehen und
das Prinzip erneut anwenden, solange bis man beim größten gemeinsamen Teiler
angekommen ist.
Ist beispielsweise 𝑎 = 72 und 𝑏 = 45, so ist der größte gemeinsame Teiler dieser
beider Zahlen identisch mit dem der Zahlen 45 und (72 − 45) = 27. erneut kann
man die Differenz beider Zahlen bilden und erhält damit das Zahlenpaar 27 und
(45−27) = 18; ein wiederholtes Anwenden des gleichen Prinzips liefert das zunächst
das Zahlenpaar 18 und (27 − 18) = 9 und schließlich 9 und 9; der größte gemeinsame
Teiler beider Zahlen ist somit 9.
In Python lässt sich diese zweite, schnellere Variante des Euklidschen Algorithmus dank
des Modulo-Operators % mit nur sehr wenig Code implementieren.
80
def gcd_simple(a, b):
'''Quite simple implementation of Euclid's Algorithm.'''
while b != 0:
tmp = a % b
a = b
b = tmp
return a
Dieser Code lässt sich noch weiter optimieren. Der Trick der folgenden Implementie-
rung besteht darin, dass der Zuweisungsoperator = eine geringere Priorität besitzt als der
Modulo-Operator, und somit erst die rechte Seite ausgewertet wird, bevor die Ergebnisse
in die links angegebenen Variablen gespeichert werden; dies erspart das Speichern der
Zwischenergebnisse in temporären Variablen:
Hat man den größten gemeinsamen Teiler gefunden, so kann auch das kleinste gemeinsame
Vielfache zweier Zahlen einfach berechnet werden: Man multipliziert beide Zahlen mit-
einander und dividiert das Ergebnis anschließend durch den größten gemeinsamen Teiler.
In Python könnte die entsprechende Funktion also folgendermaßen aussehen:
Möchte man das kleinste gemeinsame Vielfache nicht nur zweier, sondern einer Liste mit
beliebig vielen ganzen Zahlen ermitteln, so müsste man die obigelcm()-Funktion iterativ
auf die einzelnen Elemente der Liste anwenden. Nutzt man hierfür die Funktion reduce()
aus dem Standard-Modul functools , so lässt sich der Algorithmus folgendermaßen imple-
mentieren (Quelle: Stackoverflow):
import functools as ft
def lcmm(*args):
'''turn lcm of args.'''
return ft.reduce(lcm, args)
# Beispiel:
. . . to be continued . . .
81
ipython – eine Python-Entwicklungsumgebung
Ipython ist ein Interpreter-Frontend, das vielerlei nützliche Features zum interaktiven
Entwickeln von Python-Projekten bietet. Er kann durch das gleichnamige Paket installiert
werden:
Die beiden letzten Pakete ermöglichen es, Ipython mit einer graphischen Oberfläche oder
als Anwendung in einem Webbrowser zu starten. Nach der Installation kann das Pro-
gramm in einer Shell mittels ipython3 oder als graphische Oberfläche mittels ipython3
qtconsole aufgerufen werden.
Gibt man in Ipython einen Python-Ausdruck ein und drückt Enter, so wird dieser ausge-
wertet. Besteht der Ausdruck beispielsweise aus einem einzelnen Variablennamen, so wird
eine String-Version dieser Variablen ausgegeben.
Navigationshilfen
Ipython bietet gegenüber dem normalen Python-Interpreter für ein interaktives Arbeiten
am Quellcode nicht nur ein Syntax-Highlighting, sondern auch folgende Funktionen:
Tab-Vervollständigung
Während man einen Python-Ausdruck oder einen Dateinamen schreibt, kann man diesen
durch Drücken der Tab-Taste vervollständigen. Gibt es mehrere Möglichkeiten zur Ver-
vollständigung, so werden diese aufgelistet; bei Nutzung der Qt-Konsole kann zwischen
den einzelnen Möglichkeiten durch erneutes Drücken von Tab gewechselt und die Auswahl
mit Enter bestätigt werden.
Gibt man einen Modulnamen ein, gefolgt von ., so werden durch Drücken von Tab alle
Funktionen des Moduls aufgelistet; Attributs- und Funktionsnamen, die mit _ oder __
beginnen, werden allerdings als „privat“ gewertet und ignoriert. Gibt man zusätzlich den
einleitenden Unterstrich ein, so lassen auch diese Attributs- beziehungsweise Funktions-
namen mit Tab auflisten und vervollständigen.
Weitere Tastenkürzel
Navigation:
Ctrl k Lösche vom Cursor bis zum Ende der aktuellen Zeile
82
Code-History:
Ctrl ↑: History rückwärts nach Aufruf durchsuchen, der genauso beginnt wie der
aktuell eingegebene Text
Ctrl ↓: History vorwärts nach Aufruf durchsuchen, der genauso beginnt wie der
aktuell eingegebene Text
Ctrl r: History rückwärts nach Aufrufen durchsuchen, die den eingegebenen Text
als Muster beinhalten
Die letzten drei eingegeben Code-Zeilen können in Ipython zudem über die Variablen _,
__ und ___ referiert werden.
Startet man Ipython mittels ipython3 als Shell-Anwendung, so kann (abhängig von den
Einstellungen des jeweiligen Shell-Interpreters) nur begrenzt weit „zurück scrollen“. Ruft
man in Ipython Funktionen auf, die eigentlich sehr lange Ausgaben auf dem Bildschirm
erzeugen würden, so kann man diese unterdrücken, indem man an die Anweisung ein
; anhängt. Dies hat keine Auswirkung auf die Anweisung selbst, hilft aber dabei, die
Interpreter-Sitzung übersichtlich zu halten.
Informationen zu Objekten
Gibt man vor oder nach einem Variablennamen ein ? an, so werden ausführliche Informa-
tionen zur jeweiligen Variable angezeigt. Setzt man das Fragezeichen vor oder nach einen
Funktions- oder Klassennamen, so wird auch der Docstring der jeweiligen Funktion oder
Klasse angezeigt:
print?
# Ergebnis:
# Type: builtin_function_or_method
# String form: <built-in function print>
# Namespace: Python builtin
# Docstring:
# print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Schreibt man ?? anstelle von ?, so wird zusätzlich der Quellcode des jeweiligen Objekts
angezeigt.
83
magic-Funktionen
In Ipython ist es möglich, einige zusätzliche Funktionen aufzurufen; diese nur in Ipython-
Sitzungen definierten Funktionen werden als magic-Funktionen bezeichnet und mit % bzw.
%% eingeleitet. Mittels %lsmagic werden beispielsweise alle derartigen Funktionen aufge-
listet:
%lsmagic
# Ergebnis:
Durch eine Eingabe von %automagic im Ipython-Interpreter werden im Verlauf der Sit-
zung die Namen der Magic-Funktionen in den globalen Namensraum aufgenommen. Im
folgenden kann damit wahlweise pwd oder %pwd
eingegeben werden, um den Namen des aktuellen Arbeitsverzeichnisses anzuzeigen; das
beziehungsweise die %-Zeichen können anschließend also weggelassen werden.
%precision %.4g
84
Mit dieser Einstellung erhält man Ergebnisse mit wissenschaftlicher „e-Notation“ darge-
stellt, wobei maximal drei Nachkommastellen ausgegeben werden; beispielsweise liefert
auf diese Weise die Eingabe 5/100000000000000000000 das Ergebnis 5e-20.
Ipython kennt – ebenso wie der Standard-Python-Interpreter – zwei Arten von Anweisun-
gen: Zum einen „simple“ einzeilige Anweisungen, zum anderen „zusammengesetzte“ Anwei-
sungen, die aus mehreren Zeilen bestehen. In Ipython wird eine solche Block-Anweisung,
die stets mit einer leeren Zeile endet, auch als „Zelle“ bezeichnet.
Die line magic-Funktionen beziehen sich auf eine einzelne, einzeilige Anweisung; den
cell magic-Funktionen werden hingegen der jeweiligen Anweisung weitere Zeilen ange-
fügt. Beispielsweise kann mittels %% writefile dateiname der unmittelbar folgenden
Text (ohne Anführungszeichen!) in eine Datei geschrieben werden, bis die Eingabe durch
ein zweimaliges Drücken von Enter beendet wird.
%%writefile test.txt
Hallo
Welt!
Mittels %%writefile -a wird der folgende Text an die angegebene Datei angehängt; eine
Eingabe von leeren Zeilen oder von formatiertem Text ist so allerdings nicht möglich, die
unmittelbar folgende Texteingabe wird „as it is“ geschrieben.
Um dieses Problem zu umgehen, kann man die Magic-Funktion %cpaste aufrufen: An-
schließend wird der gesamte (beispielsweise mittels Paste) eingefügte Text als eine einzige
Eingabe-Zelle interpretiert – bis Ctrl d gedrückt wird, oder eine Textzeile eingegeben
wird, die lediglich die Zeichenkette -- enthält.
Auf diese Weise kann man beispielsweise Vim mit dem Plugin Vicle als Editor verwenden
und von dort aus Code an einen Ipython-Shell-Interpreter senden.
Python-Skripte aufrufen
85
%run path/script.py [arguments]
Befindet man sich bereits im Pfad der Programmdatei oder wechselt mittels os.
chdir(path) dorthin, so kann die Pfadangabe im obigen Aufruf weggelassen werden.
Der obige Aufruf entspricht dem üblichen Aufruf von python3 path/script.py in einer
Shell. Benötigt das Skript gegebenenfalls weitere Argumente, so können diese im Anschluss
an die Pfadangabe des Skripts angegeben werden. Ist das aufgerufene Skript fehlerhaft
und/oder benötigt es zu lange zur Ausführung, so kann es mit Ctrl c unterbrochen
werden (KeyboardInterrupt).
Ein Vorteil der %run-Anweisung liegt darin, dass alle im aufgerufenen Skript definierten
Variablen und Funktionen importiert und anschließend in der interaktiven Sitzung genutzt
werden können (als wären sie direkt eingeben worden). Ein weiterer Vorteil liegt darin,
dass beim Aufruf von run zusätzliche Optionen angegeben werden können:
Mit %run -t („timer“) wird die Laufzeit des Python-Skript in Kurzform dargestellt.
Der Timer listet auf, wie viel Zeit beim Ausführen des Skripts für System-Aufrufe,
wie viel auf benutzerspezifische Rechenschritte und wie viel Gesamt benötigt wurde.
Mit %run -t („profiler“) wird die Laufzeit der einzelnen im Python-Skript aufgeru-
fenen Anweisungen detailliert dargestellt.
Der Profiler listet dabei auf, wie häufig eine Funktion aufgerufen wurde und wie viel
Zeit dabei je Ausführung beziehungsweise insgesamt benötigt wurde.
Der Debugger durchläuft das Programm Anweisung für Anweisung und hält dabei
an vorgegebenen Breakpoints oder bei nicht abgefangenen Exceptions; man kann
sich dann beispielsweise die Werte von Variablen anzeigen lassen, die für den auf-
tretenden Fehler verantwortlich sein können.
Debugging
86
Umgekehrt kann man den Inhalt von Python-Variablen an die Shell-Anweisung übergeben,
indem man der Variablen ein $-Zeichen voranstellt. Man könnte also !echo "$files
eingeben, um die in der Variablen files gespeicherten Inhalte mittels echo auszugeben.
Konfigurationen
Eigene Konfigurationen lassen sich in Ipython mittels so genannter „Profile“ festlegen.
Auf diese Weise kann beispielsweise festgelegt werden, welche Module beim Start von
Ipython automatisch geladen oder welche Variablen standardmäßig definiert werden sol-
len; die Ipython-Profile ermöglichen darüber hinaus weitere Möglichkeiten, das Aussehen
und Verhalten des Interpreters zu steuern.
Hierdurch wird das Profil mit dem angegebenen Namen im Verzeichnis ~/.ipython neu
angelegt; lässt man den Profilnamen weg, so wird das Profil automatisch default genannt.
Bei künftigen Sitzungen wird, sofern vorhanden, das Profil default automatisch geladen,
außer man wählt startet Ipython explizit mit dem angegebenen Profilnamen:
ipython_config.py: Diese Datei wird immer aufgerufen, wenn Ipython mit dem
angegebenen Profil gestartet wird.
87
# sample ipython_config.py
# Configuration file for ipython.
c = get_config()
c.TerminalInteractiveShell.history_length = 10000
Die einzelnen Optionen können bei Bedarf auch innerhalb einer laufenden Sitzung
geändert werden; hierzu muss man lediglich eine Anweisung der Form %config
InteractiveShell.autoindent = True eingeben.
Die Matplotlib ist eine umfangreichste Bibliothek, mit deren Hilfe verschiedene Dia-
grammtypen wie Linien-, Stab- oder Kuchendiagramme, Histogramme, Boxplots, Kon-
tourdiagramme, aber auch dreidimensionale Diagramme und Funktionenplots auf einfache
Weise erstellt werden können.
88
Die Matplotlib ist nicht im Python3-Standard enthalten und muss daher nachinstalliert
werden :
Das zweite Paket ist notwendig, um geplottete Diagramme in einer graphischen Bedieno-
berfläche anzeigen zu können.
Das erste Paket ist nützlich, um Einstellungen für die Matplotlib vorzunehmen; das zwei-
te beinhaltet unter anderem die wichtige plot()-Funktion, die zum Erstellen von 2D-
Graphiken genutzt werden kann:
# Diagramm anzeigen:
plt.show()
Durch einen Aufruf von plt.show() wird das zuvor definierte Diagramm in einem gra-
phischen Ausgabefenster angezeigt:
89
Schließt man das Ausgabefenster wieder (beispielsweise durch Drücken von Ctrl w), so
kann man mit der Ipython-Sitzung fortfahren.
Wie man im obigen Beispiel sieht, gibt es zahlreiche Möglichkeiten, das Aussehen des
Diagramms zu beeinflussen:
Beim Setzen von derartigen Optionen für ein Diagramm muss prinzipiell nicht auf die
Reihenfolge geachtet werden; es kann allerdings eine existierende Optionen durch eine
später eingegebene Option überschrieben (oder korrigiert) werden.
Wird plt.plot() mit nur einer Zahlen-Liste als Argument aufgerufen, so werden
diese automatisch durchnummeriert (beginnend mit 0); für die 𝑥-Achse wird dann
diese Nummerierung als Wertebereich verwendet.
Wird plt.plot() mit Zahlen-Listen als Argument aufgerufen, so wird die erste
Liste als Wertebereich der 𝑥-Achse und die zweite Liste als Wertebereich der 𝑦-
Achse angesehen.
Zusätzlich zu der oder den Zahlen-Listen kann der Funktion plt.plot() als letztes
Argument eine Zeichenkette übergeben werden, welche die Farbe und Form der
Diagramm-Linie festlegt:
90
– Zu Beginn dieser Zeichenkette kann die Farbe der Diagrammlinie festgelegt
werden:
Symbol Farbe
b blue
c cyan
g green
m magenta
r red
y yellow
k black
w white
– Am Ende dieser Zeichenkette kann die Form der Diagrammlinie festgelegt wer-
den:
Symbol Form
- Durchgezogene Linie
-- Gestrichelte Linie
-. Abwechselnd gestrichelte und gepunktete Linie
: Gepunktete Linie
o Einzelne Punkte, Darstellung als farbige Kreise
s Einzelne Punkte, Darstellung als farbige Rechtecke
D Einzelne Punkte, Darstellung als Diamant-Form
^ Einzelne Punkte, Darstellung als farbige Dreiecke
x Einzelne Punkte, Darstellung als farbige x-Zeichen
* Einzelne Punkte, Darstellung als farbige *-Zeichen
+ Einzelne Punkte, Darstellung als farbige +-Zeichen
Eine vollständige Liste möglicher Marker findet sich hier. Es ist auch möglich, bei-
spielsweise mittels 'b' nur die Linienfarbe auf blue oder mittels '--' nur die Lini-
enform als gestrichelte Linie festzulegen.
Als Alternative zu der zuletzt genannten Festlegung von Farbe und Form einer
Diagrammlinie kann für das obige Beispiel auch folgende explizite Syntax gewählt
werden:
Diese Syntax ist zwar mit mehr Schreibarbeit verbunden, ermöglicht es allerdings,
beispielsweise bei einem Linien-Plot mit einem weiteren Attribut linewith=2.0 die
Linienstärke auf den doppelten Wert zu setzen.
Möchte man mehrere Linien in einem einzelnen Diagramm darstellen, so muss man le-
diglich die Funktion plt.plot() mehrfach mit den jeweiligen Wertelisten aufrufen – alle
91
Linien werden dadurch in das selbe Diagramm geplottet. Erst durch eine Eingabe von
plt.show() wird das fertige Diagramm auf dem Bildschirm ausgegeben.
Beispiel:
# Diagramm-Gitter einblenden:
plt.grid(True)
# Diagramm ausgeben:
plt.show()
Ergebnis:
Diagramme speichern
Eine andere Möglichkeit besteht darin, das Diagramm vor einem Aufruf von plt.show()
mittels folgender Anweisung zu speichern:
92
# Speichern als PNG-Datei:
plt.savefig('/pfad/dateiname.png')
Ist der Aufruf von plt.show() beendet, so verfällt nämlich das bisherige Diagramm mit-
samt allen dafür getroffenen Festlegungen. Dies hat einerseits den Vorteil, dass man unmit-
telbar mit der Eingabe des nächsten Diagramms beginnen kann, ohne die Einstellungen
erst zurücksetzen zu müssen. Andererseits ist ein Ändern des bisherigen Diagramms nur
möglich, indem man die bisherigen Eingaben über die History-Funktion des Interpreters
(↑-Taste) zurückholt und als Vorlage für ein neues Diagramm nimmt.
Anstelle einer Zahlenliste kann der Funktion plt.plot() auch eine beziehungsweise
zwei Zahlenbereiche übergeben werden, die beispielsweise mittels np.arange() oder np.
linspace() aus dem numpy -Modul generiert wurden. Dies hat den Vorteil, dass man mit
einer sehr guten Rechen-Performance die Wertebereiche in sehr kleine Schritte unterteilen
kann und die erstellten Linien somit nahezu „glatt“ erscheinen:
Beispiel:
import numpy as np
# Sinus-Kurve plotten:
plt.plot(x, y)
plt.axis( [0, 7, -1.5, 1.5] )
plt.grid(True)
plt.show()
Ergebnis:
93
Anpassung von Matplotlib-Diagrammen
Matplotlib-Diagramme haben allgemein folgenden Aufbau:
Die Basis eines jeden Diagramms ist also ein Figure-Objekt (mit möglichem Titel), das
eigentliche Diagramm wird durch den Wertebereich der Achsen (axes) festgelegt. Insbe-
sondere muss zwischen axes und axis unterschieden werden: Die letztere Bezeichnung
bezieht sich nur auf entweder die 𝑥- oder die 𝑦 -Achse.
Anhand des Sinus-Plots aus dem letzten Abschnitt soll im folgenden Beispiel gezeigt
werden, wie man mittels der obigen Objekte das Aussehen eines Matplotlib-Diagramms
1
anpassen beziehungsweise verbessern kann.
import numpy as np
import matplotlib.pyplot as plt
# Diagramm-Linien plotten:
plt.plot(x, cos_x)
plt.plot(x, sin_x)
# Diagramm anzeigen:
plt.show()
Mit der obigen Plot-Anweisung erhält man – ohne weitere Einstellungen – folgendes Dia-
gramm:
94
Abb. 2: Sinus- und Cosinus-Plot mit Basis-Einstellungen
Auf diese Weise kann man sich mit sehr wenig Aufwand ein Bild von einer mathematischen
Funktion verschaffen. Dass nur eine minimale Code-Menge nötig ist, liegt auch daran,
dass in den Matplotlib-Funktionen für viele Einstellungen Standard-Werte vorgegeben
sind. Würde man alle diese Werte explizit angeben, so würde das obige Code-Beispiel
folgendermaßen aussehen:
1 # Module importieren
2 import numpy as np
3 import matplotlib.pyplot as plt
4
5 # Werte-Listen für eine Sinus- und Cosinus-Funktion erstellen:
6 x = np.linspace(-np.pi, np.pi, 500, endpoint=True)
7 cos_x = np.cos(x)
8 sin_x = np.sin(x)
9
10 # Eine neues Matplot-Figure-Objekt mit 8x6 Zoll und
11 # einer Auflösung von 100 dpi erstellen:
12 plt.figure(figsize=(8, 6), dpi=80)
13
14 # In diese Abbildung ein 1x1 großes Diagramm-Gitter erstellen;
15 # Als aktuelles Diagramm wird das erste dieses Gitters ausgewählt:
16 plt.subplot(111)
17
18 # Cosinus-Funktion mit blauer Farbe, durchgehender Linie und 1 Pixel
19 # Linienbreite plotten:
20 plt.plot(x, cos_x, color="blue", linewidth=1.0, linestyle="-")
21
22 # Sinus-Funktion mit grüner Farbe, durchgehender Linie und 1 Pixel
23 # Linienbreite plotten:
24 plt.plot(x, sin_x, color="green", linewidth=1.0, linestyle="-")
25
26 # Grenzen für die x-Achse festlegen:
27 plt.xlim(-4.0, 4.0)
28
95
(Fortsetzung der vorherigen Seite)
Die Ausgabe dieses Codes ist mit dem obigen Diagramm absolut identisch. Man kann die-
ses „ausführlichere“ Code-Beispiel allerdings sehr gut als Ausgangsbasis für verschiedene
Anpassungen verwenden.
Die Linien werden im ursprünglichen Diagramm zudem mit einer Linienbreite von nur 1 px
gedruckt. Würde man dieses Diagramm beispielsweise mit einem Schwarz-Weiß-Drucker
drucken (und die gedruckte Seite womöglich anschließend noch kopieren), so wären die
Linien nicht mehr gut zu erkennen – zudem hätten die Linien ähnliche Grau-Werte. Um
dies zu verbessern, kann man im obigen Code-Beispiel die Zeilen 20 und 24 durch folgende
Zeilen ersetzen:
Gibt man zudem keinen Wertebereich für die 𝑥- und 𝑦 -Achse an, verwendet die Matplot-
lib einfach die Minima und Maxima der darzustellenden Werte als Diagramm-Grenzen
(zum betraglich nächst größeren Integer-Wert aufgerundet); die Diagramm-Linie stößt
somit an den Diagramm-Grenzen an. Möchte man hier einen „weicheren“ Übergang, also
nicht anstoßende Diagrammlinien, so kann ein geringfügig größerer Wertebereich für die
Diagramm-Grenzen gewählt werden. Hierzu kann man im obigen Code-Beispiel die Zeilen
27 und 30 durch folgende Zeilen ersetzen:
96
# Wertebereiche der Achsen anpassen:
plt.xlim(x.min()*1.1, x.max()*1.1)
plt.ylim(cos_x.min()*1.1, cos_x.max()*1.1)
Mit diesen Anpassungen erhält man bei einem Aufruf von plt.show() nun folgendes
Diagramm:
Zur Darstellung der trigonometrischen Funktionen ist die gewöhnliche Skalierung der 𝑥-
Achse nicht ideal: Man kann damit beispielsweise nur näherungsweise ablesen, an welchen
Stellen die Funktionen Nullstellen oder Maxima haben. Praktischer wäre es, die Skalierung
der 𝑥-Achse anhand der Kreiszahl 𝜋 festzulegen. Hierzu kann man im obigen Code-Beispiel
die Zeile 33 durch folgende Zeile ersetzen:
# Auf der x-Achse fünf Bezugspunkte (als Vielfache von pi) festlegen:
plt.xticks( [-np.pi, -np.pi/2, 0, np.pi/2, np.pi] )
Plottet man das so abgeänderte Diagramm, so bekommt man auf der 𝑥-Achse die nume-
rischen Werte angezeigt, also beispielsweise 3.142 anstelle von 𝜋. Glücklicherweise kann
man beim Aufruf von plt.xticks() nicht nur die Position der Ticks, sondern durch
Angabe einer zweiten Liste auch ihre Beschriftung festlegen, und hierfür optional auch
LaTeX-Formelzeichen nutzen:
# Auf der x-Achse fünf Bezugspunkte (als Vielfache von pi) festlegen
# und mittels LaTeX-Symbolen beschriften:
plt.xticks( [-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[ r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$']
)
97
Das r vor den einzelnen Zeichenketten bewirkt, dass diese als raw angesehen werden, also
Sonderzeichen wie $ nicht mit einem zusätzlichen \-Zeichen versehen werden müssen.
Im obigen Beispiel wurde auch die Beschriftung der 𝑦 -Achse angepasst, damit die Schrift-
art identisch ist. Als Ergebnis erhält man bei einem Aufruf von plt.show() damit fol-
gendes Diagramm:
Diagramm-Achsen verschieben:
Das Achsen-Objekt axes eines Diagramms hat eine Eigenschaft, die mit spines bezeich-
net wird; darin wird festgelegt, an welcher Stelle die Achsen dargestellt werden sollen.
Standardmäßig wird in der Matplotlib die 𝑦 -Achse am linken Rand des Diagramms ge-
druckt. Dies hat den Vorteil, dass man auch den rechten Rand für das zusätzliche Plotten
einer zweiten Kurve als Werte-Achse nutzen kann, sofern sich die Wertebereiche beider
Linien stark voneinander unterscheiden.
# Die linke Diagrammachse auf den Bezugspunkt '0' der x-Achse legen:
ax.spines['left'].set_position(('data',0))
98
(Fortsetzung der vorherigen Seite)
# Die untere Diagrammachse auf den Bezugspunkt '0' der y-Achse legen:
ax.spines['bottom'].set_position(('data',0))
Als Ergebnis erhält man damit bei einem Aufruf von plt.show() folgendes Diagramm:
Diese Darstellungsform ist zwar elegant, doch werden in diesem Fall die Beschriftungen
der 𝑥- und 𝑦 -Achse teilweise durch die Funktionsgraphen verdeckt. Als Workaround kann
man einerseits Schriftgröße der Achsenbeschriftung ändern, und andererseits diese durch
eine halb-transparente Umrandung hervorheben. Hierzu kann man folgenden Code vor
der Anweisung plt.show() einfügen:
Als Ergebnis erhält man damit durch einen Aufruf von plt.show():
Normalerweise werden Diagramme bei der Textsatzung mit einer Bildunterschrift („Capti-
on“) eingebunden; meist wird dabei auch eine Abbildungs-Nummer mit eingefügt, so dass
das Diagramm aus dem Text heraus eindeutig referenziert werden kann. Erstellt man ein
Diagramm hingegen für eine Pinnwand oder eine Overhead-Folie / Beamer-Präsentation,
so ist ein groß gedruckter Titel über dem Diagramm bisweilen nützlich. Ein solcher kann
folgendermaßen zum Diagramm hinzugefügt werden:
# Titel hinzufügen:
plt.title('Sinus und Cosinus', fontsize=20, color='gray')
99
Abb. 6: Sinus- und Cosinus-Plot mit anderer Positionierung der Achsen und hervorgeho-
bener Achsen-Bsechriftung.
Auch hier kann bei Bedarf wieder LaTeX-Code im Titeltext verwendet werden.
Als weitere Verbesserung ist es sehr nützlich, wenn in einem Diagramm mit mehreren
Linien als „Legende“ angezeigt wird, welche Bedeutung die einzelnen Linien haben. Hierzu
kann man bei den einzelnen plt.plot()-Anweisungen zusätzlich einen label-Parameter
angeben und anschließend die Legende mittelsplt.legend() anzeigen:
# Plots mit einem Label versehen:
plt.plot(x, cos_x, color="blue", linewidth=2.5, linestyle="-", label=r'$\cos(x)$
˓→')
# Legende einblenden:
plt.legend(loc='upper left', frameon=True)
Als zusätzliche Beschriftung können noch weitere Text-Elemente in das Diagramm aufge-
nommen werden. Besondere Stellen lassen sich zudem mit Pfeilen oder Hilfslinien hervor-
heben.
100
(Fortsetzung der vorherigen Seite)
plt.annotate(r'$\sin(\frac{2\pi}{3}) = \frac{\sqrt{3}}{2}$',
xy=(pos, np.sin(pos)), xycoords='data',
xytext=(+10, +30), textcoords='offset points', fontsize=16,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=.2"))
. . . to be continued . . .
Links
Numpy ist eine Python-Bibliothek mit Datentypen und Funktionen, die für numerische
Berechnungen optimiert sind. Meist lassen sich solche Aufgaben zwar auch mit den norma-
101
len Python-Funktionen berechnen, gerade bei großen Zahlenmengen ist Numpy allerdings
wesentlich schneller.
Numpy ist nicht im Python3-Standard enthalten und muss daher separat installiert wer-
den :
Der zentrale Objekttyp in Numpy ist das ndarray (meist kurz „Array“ genannt), das viele
Gemeinsamkeiten mit der normalen Liste aufweist. Ein wesentlicher Unterschied besteht
allerdings darin, dass alle im Array gespeicherten Elemente den gleichen Objekttyp haben
müssen. Die Größe von Numpy-Arrays kann zudem nicht verändert werden, und es sind
keine leeren Objekte erlaubt. Durch derartige Eigenschaften können Numpy-Arrays vom
Python-Interpreter schneller durchlaufen werden. Darüber hinaus stellt Numpy etliche
grundlegende Funktionen bereit, um mit den Inhalten solcher Arrays zu arbeiten und/oder
Änderungen an solchen Arrays vorzunehmen.
Numpy-Arrays erstellen
Ein neues Numpy-Array kann folgendermaßen aus einer normalen Liste, deren Elemente
alle den gleichen Datentyp haben müssen, erzeugt werden:
import numpy as np
nums = [1,2,3,4,5]
a
# Ergebnis: array([1, 2, 3, 4, 5])
Die beim Funktionsaufruf von array() übergebene Liste kann auch aus mehreren Teillis-
ten bestehen, um beispielsweise zeilenweise die Werte einer Matrix als Numpy-Array zu
speichern:
m1
# Ergebnis:
# array([[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]])
Durch ein zweites Argument kann beim Aufruf der array()-Funktion der Datentyp der
Elemente explizit festgelegt werden. Beispielsweise könnten im obigen Beispiel durch eine
102
zusätzliche Angabe von dtype=float die in der Liste enthaltenen Integer-Werte automa-
tisch in Gleitkomma-Zahlen umgewandelt werden.
Da auch Matrizen voller Nullen oder Einsen häufig vorkommen, können diese mittels der
dafür vorgesehenen Funktionen zeros() bzw. ones() erzeugt werden. Dabei wird als
erstes Argument ein Tupel als Argument angegeben, welches die Anzahl an Zeilen und
Spalten der Matrix festlegt, sowie als zweites Argument wiederum optional der Datentyp
der einzelnen Elemente:
m2
# Ergebnis:
# array([[0, 0, 0],
# [0, 0, 0]])
Mittels der Funktion arange() kann ein (eindimensionales) Numpy-Array auf Grundlage
eines Zahlenbereichs erstellt werden:
r
# Ergebnis:
# array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ,
# 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1,
# 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2,
# 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3,
# 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5. , 5.1, 5.2, 5.3, 5.4,
# 5.5, 5.6, 5.7, 5.8, 5.9, 6. , 6.1, 6.2, 6.3, 6.4, 6.5,
# 6.6, 6.7, 6.8, 6.9, 7. , 7.1, 7.2, 7.3, 7.4, 7.5, 7.6,
# 7.7, 7.8, 7.9, 8. , 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7,
# 8.8, 8.9, 9. , 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8,
# 9.9])
Die Funktion arange() verhält sich also genauso wie die Funktion range() , liefert aller-
1
dings ein Numpy-Array mit den entsprechenden Werten als Ergebnis zurück.
1 Auch bei der arange()-Funktion ist die untere Grenze im Zahlenbereich enthalten, die obere jedoch
nicht.
Das optionale dritte Argument gibt, ebenso wie bei range() , die Schrittweite zwischen den beiden Zah-
lengrenzen an. Ist der Zahlenwert der unteren Bereichsgrenze größer als derjenige der oberen Bereichsgren-
ze, so muss ein negativer Wert als Schrittweite angegeben werden, andererseits bleibt das resultierende
Array leer.
103
Eine zweite, sehr ähnliche Möglichkeit zur Erstellung eines Numpy-Arrays bietet die Funk-
tion linspace(): Bei dieser wird allerdings die Anzahl der Schritte zwischen dem Start-
und dem Endwert angegeben; die Schrittweite wird dann automatisch berechnet.
l
# Ergebnis:
# array([ 0. , 0.1010101 , 0.2020202 , 0.3030303 ,
# 0.4040404 , 0.50505051, 0.60606061, 0.70707071,
# 0.80808081, 0.90909091, 1.01010101, 1.11111111,
# 1.21212121, 1.31313131, 1.41414141, 1.51515152,
# 1.61616162, 1.71717172, 1.81818182, 1.91919192,
# 2.02020202, 2.12121212, 2.22222222, 2.32323232,
# 2.42424242, 2.52525253, 2.62626263, 2.72727273,
# 2.82828283, 2.92929293, 3.03030303, 3.13131313,
# 3.23232323, 3.33333333, 3.43434343, 3.53535354,
# 3.63636364, 3.73737374, 3.83838384, 3.93939394,
# 4.04040404, 4.14141414, 4.24242424, 4.34343434,
# 4.44444444, 4.54545455, 4.64646465, 4.74747475,
# 4.84848485, 4.94949495, 5.05050505, 5.15151515,
# 5.25252525, 5.35353535, 5.45454545, 5.55555556,
# 5.65656566, 5.75757576, 5.85858586, 5.95959596,
# 6.06060606, 6.16161616, 6.26262626, 6.36363636,
# 6.46464646, 6.56565657, 6.66666667, 6.76767677,
# 6.86868687, 6.96969697, 7.07070707, 7.17171717,
# 7.27272727, 7.37373737, 7.47474747, 7.57575758,
# 7.67676768, 7.77777778, 7.87878788, 7.97979798,
# 8.08080808, 8.18181818, 8.28282828, 8.38383838,
# 8.48484848, 8.58585859, 8.68686869, 8.78787879,
# 8.88888889, 8.98989899, 9.09090909, 9.19191919,
# 9.29292929, 9.39393939, 9.49494949, 9.5959596 ,
# 9.6969697 , 9.7979798 , 9.8989899 , 10. ])
Setzt man im obigen Beispiel endpoint=False, so ist das mit linspace() erzeugte Array
l mit dem Array r aus dem vorherigen Beispiel identisch.
nums = [1,2,3,4,5]
a = np.array(nums)
104
(Fortsetzung der vorherigen Seite)
a[3]
# Ergebnis: 4
a[-1]
# Ergebnis: 5
Als positive Indizes sind Werte zwischen i >= 0 und i < len(array) möglich; sie liefern
jeweils den Wert des i+1-ten Listenelements als Ergebnis zurück. Für negative Indizes
sind Werte ab i <= -1 möglich; sie liefern jeweils den Wert des i-ten Listenelements –
vom Ende der Liste her gerechnet – als Ergebnis zurück. Die Indizierung kann ebenso
genutzt werden, um den Inhalt des Arrays an einer bestimmten Stelle zu verändern:
a[-1] = 10
a
# Ergebnis: array([1, 2, 3, 4, 10])
r = np.arange(10)
# Intervall selektieren:
r[3:8]
# Ergebnis: array([3, 4, 5, 6, 7])
r[3:8:2]
# Ergebnis: array([3, 5, 7])
Wie üblich wird bei Slicings die untere Grenze ins Intervall mit eingeschlossen, die obere
nicht. Mit der Syntax start:stop:step kann bei Slicings zudem festgelegt werden, dass
innerhalb des ausgewählten Zahlenbereichs nur jede durch die Zahl step bezeichnete
Zahl ausgewählt wird. Wird für start oder step kein Wert angegeben, so wird der ganze
Bereich ausgewählt:
r[5::-1]
# Ergebnis: array([5, 4, 3, 2, 1, 0])
Slicings können bei Zuweisungen von neuen Werten auch auf der linken Seite des =-
Zeichens stehen. Auf diese Weise kann bisweilen auf eine for-Schleife verzichtet und der
Code somit lesbarer gemacht werden.
105
Um in mehrdimensionalen Numpy-Arrays Werte zu selektieren, wird folgende Syntax
verwendet:
m
# Ergebnis:
# array([[1, 2, 3],
# [4, 5, 6]])
m[1][2]
# Ergebnis: 6
Bei Numpy-Arrays können die „Verschachtelungstiefen“ wie bei Listen durch eine mehrfa-
che Anwendung des Index-Operators [] aufgelöst werden; ebenso ist für das obige Beispiel
allerdings auch die Syntax m3[1,2] erlaubt und auch üblich. Bei der Auswahl eines Ele-
ments aus einer Matrix können also innerhalb des Index-Operators die Zeile und Spalte
durch ein Komma getrennt ausgewählt werden; Slicings sind hierbei ebenfalls möglich.
r = np.arange(10)
r
# Ergebnis: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
r+1
# Ergebnis: array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
2 Die gleichnamigen Funktionen aus dem math-Modul können also auf einzelne Elemente eines Numpy-
Arrays, nicht jedoch auf das ganze Array an sich angewendet werden. Letzteres könnte man zwar bei-
spielsweies mittels einer for-Schleife erreichen, doch die Ausführung des Codes bei Verwendung der
106
(Fortsetzung der vorherigen Seite)
r**2
# Ergebnis: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81])
np.sqrt(r**4)
# Ergebnis: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81])
np.sin(r)
# Ergebnis: array([ 0. , 0.84147098, 0.90929743, 0.14112001, -0.
˓→7568025 ,
Zusätzlich gibt es in Numpy Funktionen, die speziell für Zahlenreihen und Matrizen vorge-
sehen sind. Beispielsweise kann mit der Numpy-Funktionen argmin() und argmax() der
Index des kleinsten und größten Elements in einem Array gefunden werden. Wendet man
diese Funktionen auf ein Matrix-Array an, so erhält man diejenige Index-Nummer des
kleinsten beziehungsweise größten Elements, die sich bei einem eindimensionalen Array
mit den gleichen Werten ergeben würde. Ist man hingegen spalten- oder zeilenweise an
den jeweiligen Minima beziehungsweise Maxima interessiert, so kann beim Aufruf dieser
beiden Funktionen als zweites Argument axis=0 für eine spaltenweise Auswertung oder
axis=1 für eine zeilenweie Auswertung angegeben werden:
a = np.array( [3,1,2,6,5,4] )
m = np.array([ [3,1,2], [6,5,4] ])
np.argmin(a)
# Ergebnis: 1
np.argmin(m)
# Ergebnis: 1
np.argmin(m, axis=0)
# Ergebnis: array([0, 0, 0])
np.argmin(m, axis=1)
# Ergebnis: array([1, 2])
. . . to be continued . . .
Links
107
pandas – eine Bibliothek für tabellarische Daten
Pandas ist eine Python-Bibliothek, die vorrangig zum Auswerten und Bearbeiten tabel-
larischer Daten gedacht ist. Dafür sind in Pandas drei Arten von Objekten definiert:
Ein Panel besteht aus einer „dreidimensionalen“ Tabelle. Die einzelnen Ebenen die-
ser Tabelle bestehen wiederum aus Dataframe-Objekten.
import pandas as pd
s = pd.Series( [5,10,15,20,25] )
s
# Ergebnis:
# 0 5
# 1 10
# 2 15
# 3 20
# 4 25
# dtype: int64
Das Series-Objekt erhält automatisch einen Index, so dass beispielsweise mittels s[0] auf
das erste Element, mit s[1] auf das zweite Element, usw. zugegriffen werden kann. Neben
diesen numerischen Indizes, die auch bei gewöhnlichen Listen verwendet werden, können
explizit auch andere Indizes vergeben werden:
s.index = ['a','b','c','d','e']
s
# Ergebnis:
# a 5
# b 10
# c 15
(continues on next page)
108
(Fortsetzung der vorherigen Seite)
# d 20
# e 25
# dtype: int64
Nun können die einzelnen Elemente zwar immer noch mit s[0], s[1], usw., aber zusätzlich
1
auch mittels s['a'], s['b'] usw. ausgewählt werden. Wird bei der Generierung eines
Series-Objekts ein Dict angegeben, so werden automatisch die Schlüssel als Indizes und
die Werte als eigentliche Listenelemente gespeichert.
Slicings
Sollen mehrere Elemente ausgewählt werden,so können die entsprechenden Indizes wahl-
weise als Liste oder als so genannter „Slice“ angegeben werden:
s[ [1,2] ]
# Ergebnis:
# b 10
# c 15
s[ 1:3 ]
# Ergebnis:
# b 10
# c 15
Bei Slicings wird, ebenso wie bei range() -Angaben, die obere Grenze nicht in den Aus-
wahlbereich mit eingeschlossen. Die Auswahl mittels Slicing hat bei Series-Objekten also
die gleiche Syntax wie die Auswahl von Listenobjekten .
Zeitreihen
dates
# <class 'pandas.tseries.index.DatetimeIndex'>
# [2000-01-01, ..., 2000-01-07]
# Length: 7, Freq: D, Timezone: None
1 Die Index-Liste kann auch bereits bei der Erzeugung eines neuen Series-Ob jekts mittels
109
Als Start- und Endpunkt werden allgemein Datumsangaben mit einer gleichen Syntax
wie im datetime-Modul verwendet. Zusätzlich kann angegeben werden, in welchen Zeit-
schritten die Zeitreihe erstellt werden soll:
weekly
# Ergebnis:
# <class 'pandas.tseries.index.DatetimeIndex'>
# [2000-01-02, ..., 2000-01-30]
# Length: 5, Freq: W-SUN, Timezone: None
hourly
# Ergebnis:
# <class 'pandas.tseries.index.DatetimeIndex'>
# [2000-01-01 08:00:00, ..., 2000-01-01 18:00:00]
# Length: 11, Freq: H, Timezone: None
import pandas as pd
# 1D-Beispiel-Dataframe erstellen:
df = pd.DataFrame( [5,10,15,20,25] )
df
# Ergebnis:
# 0
# 0 5
# 1 10
# 2 15
# 3 20
# 4 25
#
# [5 rows x 1 columns]
Als Unterschied zu einem Series-Objekt werden bei einem Dataframe sowohl die Zeilen
als auch die Spalten mit einem Index versehen.
110
Mehrspaltige Dataframes können auch über ein dict-Objekt definiert werden, wobei die
Schlüsselwerte den Spaltennamen und die damit verbundenen Werte einzelnen Daten
entsprechen, aus denen der Dataframe generiert werden soll:
# 2D-Beispiel-Dataframe erstellen:
df2 = pd.DataFrame({
'A' : 1.,
'B' : pd.date_range('2000-01-01', '2000-01-07'),
'C' : pd.Series(range(7), dtype='float32'),
'D' : np.random.randn(7),
'E' : pd.Categorical(['on', 'off', 'on', 'off', 'on', 'off', 'on']),
'F' : 'foo' })
df2
# Ergebnis:
# A B C D E F
# 0 1 2000-01-01 0 -2.611072 on foo
# 1 1 2000-01-02 1 0.630309 off foo
# 2 1 2000-01-03 2 -1.645430 on foo
# 3 1 2000-01-04 3 1.056535 off foo
# 4 1 2000-01-05 4 2.194970 on foo
# 5 1 2000-01-06 5 0.537804 off foo
# 6 1 2000-01-07 6 1.011678 on foo
Wie man sieht, wird bei Angabe eines einzelnen Wertes für eine Spalte dieser als konstant
für die ganze Spalte angenommen; listenartige Objekte hingegen müssen allesamt die
gleiche Länge aufweisen.
Datentypen
Innerhalb einer Spalte eines Dataframe-Objekts müssen alle Werte den gleichen Datentyp
aufweisen. Man kann sich die Datentypen der einzelnen Spalten folgendermaßen anzeigen
lassen:
# Datentypen anzeigen:
df2.dtypes
# Ergebnis:
# A float64
# B datetime64[ns]
# C float32
# D float64
# E category
# F object
# dtype: object
111
Daten anzeigen und sortieren
Bei längeren Datensätzen kann es bereits hilfreich sein, nur einen kurzen Blick auf den
Anfang oder das Ende der Tabelle werfen zu können. Bei Dataframe-Objekten ist dies
mittels der Funktionen head() beziehungsweise tail() möglich:
df2.head()
# Ergebnis:
# A B C D E F
# 0 1 2000-01-01 0 -2.611072 on foo
# 1 1 2000-01-02 1 0.630309 off foo
# 2 1 2000-01-03 2 -1.645430 on foo
# 3 1 2000-01-04 3 1.056535 off foo
# 4 1 2000-01-05 4 2.194970 on foo
df2.tail(3)
# Ergebnis:
# A B C D E F
# 4 1 2000-01-05 4 2.194970 on foo
# 5 1 2000-01-06 5 0.537804 off foo
# 6 1 2000-01-07 6 1.011678 on foo
Standardmäßig geben head() und tail() je fünf Zeilen aus; ist eine andere Anzahl ge-
wünscht, so kann diese als Argument angegeben werden.
Die einzelnen Bestandteile eines Dataframes, d.h. die Spaltennamen, die Index-Werte
sowie die eigentlichen Daten, können über die Attribute columns, index und values des
Dataframes abgerufen werden:
df2.columns
# Ergebnis:
# Index(['A', 'B', 'C', 'D', 'E', 'F'], dtype='object')
df2.index
# Ergebnis:
# Int64Index([0, 1, 2, 3, 4, 5, 6], dtype='int64')
df2.values
# Ergebnis:
# array([[1.0, Timestamp('2000-01-01 00:00:00'), 0.0, -2.611072451193798, 'on',
˓→'foo'],
112
(Fortsetzung der vorherigen Seite)
# dtype=object)
Statistische Übersicht
Eine Kurz-Analyse der Daten ist über die Methode describe() des Dataframes mög-
lich. Man erhält als Ergebnis eine Übersicht über die jeweiligen Mittelwerte sowie einige
statistische Streuungsmaße (Standardabweichung, größter und kleinster Wert, Quartile).
Da sich diese Größen nur für quantitative (genauer: invervall-skalierte) Merkmalswerte
bestimmen lassen, werden die jeweiligen Werte auch nur für die in Frage kommenden
Spalten angezeigt:
df2.describe()
# Ergebnis:
# A C D
# count 7 7.000000 7.000000
# mean 1 3.000000 0.167828
# std 0 2.160247 1.681872
# min 1 0.000000 -2.611072
# 25% 1 1.500000 -0.553813
# 50% 1 3.000000 0.630309
# 75% 1 4.500000 1.034107
# max 1 6.000000 2.194970
Sortiermethoden
Die Daten eines Dataframes können zudem wahlweise nach Zeilen oder Spalten oder auch
anhand der jeweiligen Werte sortiert werden:
Mit der Methode sort_index() können die Daten nach Zeilen (axis=0) oder Spal-
ten (axis=1) sortiert werden; mittels ascending=False kann zudem die Reihenfolge
der Sortierung umgekehrt werden.
113
df2.sort_index(axis=1, ascending=False)
# Ergebnis:
# F E D C B A
# 0 foo on -2.611072 0 2000-01-01 1
# 1 foo off 0.630309 1 2000-01-02 1
# 2 foo on -1.645430 2 2000-01-03 1
# 3 foo off 1.056535 3 2000-01-04 1
# 4 foo on 2.194970 4 2000-01-05 1
# 5 foo off 0.537804 5 2000-01-06 1
# 6 foo on 1.011678 6 2000-01-07 1
Wird zusätzlich das optionale Argument inline=True gesetzt, so wird nicht ein ver-
ändertes Resultat angezeigt (das beispielsweise in einer neuen Variablen gespeichert
werden könnte); vielmehr wird in diesem Fall die Änderung auch im ursprünlichen
Dataframe-Objekt übernommen.
Mit der Methode sort_value() können die Daten ihrer Größe nach sortiert werden.
Standardmäßig werden die Daten dabei zeilenweise (axis=0) und in aufsteigender
Reihenfolge (ascending=True) sortiert; bei Bedarf können diese Variablen angepasst
werden.
df2.sort_values(by='D')
# Ergebnis:
# A B C D E F
# 0 1 2000-01-01 0 -2.611072 on foo
# 2 1 2000-01-03 2 -1.645430 on foo
# 5 1 2000-01-06 5 0.537804 off foo
# 1 1 2000-01-02 1 0.630309 off foo
# 6 1 2000-01-07 6 1.011678 on foo
# 3 1 2000-01-04 3 1.056535 off foo
# 4 1 2000-01-05 4 2.194970 on foo
Auch bei dieser Sortiermethode können die Änderungen mittels inline=True nicht
nur angezeigt, sondern direkt in den Original-Dataframe übernommen werden.
Daten auswählen
Ein Zugriff auf einzelne Zeilen oder Spalten ist beispielsweise mit Hilfe des Index-
Operators [ ] möglich. Gibt man hierbei einen Spaltennamen oder eine Liste mit Spal-
tennamen an, so werden die jeweiligen Spalten ausgewählt; gibt man hingegen eine Zeilen-
nummer oder einen Zeilenbereich an, so erhält man die jeweilige(n) Zeile(n) als Ergebnis:
df2['B']
# Ergebnis:
# 0 2000-01-01
(continues on next page)
114
(Fortsetzung der vorherigen Seite)
# 1 2000-01-02
# 2 2000-01-03
# 3 2000-01-04
# 4 2000-01-05
# 5 2000-01-06
# 6 2000-01-07
# Name: B, dtype: datetime64[ns]
df2[['B','D']]
# Ergebnis:
# B D
# 0 2000-01-01 -2.611072
# 1 2000-01-02 0.630309
# 2 2000-01-03 -1.645430
# 3 2000-01-04 1.056535
# 4 2000-01-05 2.194970
# 5 2000-01-06 0.537804
# 6 2000-01-07 1.011678
df2[1:3]
# A B C D E F
# 1 1 2000-01-02 1 0.630309 off foo
# 2 1 2000-01-03 2 -1.645430 on foo
Bei Bereichsangaben mittels Slicings ist wie gewöhnlich die untere Grenze im Bereich mit
enthalten, die obere hingegen nicht.
Um auf einzelne Elemente eines Dataframes zugreifen zu können, muss sowohl eine Zeilen-
wie auch eine Reihenauswahl möglich sein. Für Dataframes ist dafür unter anderem der
.loc[]-Operator definiert, mit dem eine Zeilen- beziehungsweise Spaltenauswahl anhand
der index- beziehungsweise columns-Bezeichnungen möglich ist. Die Syntax lautet hier-
bei dataframe.loc[zeilenbereich,spaltenbereich], wobei für die Bereichsangaben
sowohl einzelne Index-Werte, Werte-Listen oder auch Slicings erlaubt sind; eine Bereichs-
Angabe von : bewirkt, dass der gesamte Zeilen- beziehungsweise Spaltenbereich ausge-
wählt werden soll.
Beispiel:
# df2.loc[1:3, ['B','D']]
# B D
# 1 2000-01-02 0.630309
# 2 2000-01-03 -1.645430
# 3 2000-01-04 1.056535
Anders als beim gewöhnlichen Auswahloperator werden bei Benutzung des .loc[]-
Operators bei Slicings beide Grenzen zum Bereich dazugerechnet.
115
Möchte man nur einen einzelnen Wert auswählen, als Resultat also einen Skalar erhalten,
so kann mit gleicher Syntax auch der .at[]-Operator verwendet werden, der für diese
Aufgabe eine geringere Rechenzeit benötigt.
Ein zweiter Auswahl-Operator für Dataframes ist der .iloc[]-Operator. Das „i“ steht
dabei für „integer“ und soll darauf hinweisen, dass dieser Auswahl sowohl für die Anga-
be des Zeilen- wie auch des Spaltenbereichs eine numerische Positionsangabe erwartet.
Wie bei einer Liste wird die erste Zeile beziehungsweise Spalte eines Dataframes intern
mit 0, die zweite mit 1, usw. nummeriert, unabhängig von den index- beziehungswei-
secolumns-Bezeichnungen. Die Syntax für den .iloc-Operator lautet also dataframe.
iloc[zeilenbereich,spaltenbereich], wobei wiederum einzelne Werte, Werte-Listen
oder auch Slicings zur Angabe der Positionen erlaubt sind:
Beispiel:
# df2.iloc[1:3,[1,3]]
# B D
# 1 2000-01-02 0.630309
# 2 2000-01-03 -1.645430
# 3 2000-01-04 1.056535
Auch beim .loc[]-Operator werden bei Slicings beide Grenzen zum Bereich dazugerech-
net.
Möchte man nur einen einzelnen Wert auswählen, als Resultat also einen Skalar erhalten,
so kann mit gleicher Syntax auch der .iat[]-Operator verwendet werden, der für diese
Aufgabe eine geringere Rechenzeit benötigt.
Oftmals interessiert man sich nur für eine Teilmenge eines Dataframes, deren Daten be-
stimmte Bedingungen erfüllen; man weiß jedoch nicht unmittelbar, an welchen Stellen
im Dataframe diese Daten abgelegt sind. Eine schnelle und elegante Methode für eine
derartige Datenauswahl besteht darin, die obigen Auswahl-Operatoren mit der jeweiligen
Bedingung anstelle einer Bereichsangabe zu verwenden.
Bei der Formulierung der Auswahl-Bedingungen kann genutzt werden, dass man bei der
Anwendung von von Vergleichsoperatoren auf Dataframes boolesche Werte erhält:
Beispiel:
116
df2['D'] > 1
# 0 False
# 1 False
# 2 False
# 3 True
# 4 True
# 5 False
# 6 True
# Name: D, dtype: bool
Anstelle der obigen Syntax kann auch df['D'].gt(0) geschrieben werden, wobei gt() für
„greater than“ steht. Diese und ähnliche Methoden gibt es sowohl für (mehrdimensionale)
Dataframes als auch für (eindimensionale) Series-Objekte; ihr Vorteil besteht darin, dass
sie sich verketten lassen. Beispielsweise liefert so df2['D'].gt(0).lt(2) den booleschen
Wert True für alle Werte, die größer als 0 und kleiner als 2 sind.
Ein Series-Objekt mit booleschen Werten, wie man sie im obigen Beispiel erhalten hat,
kann wiederum als Bereichsangabe für die oben genannten Auswahl-Operatoren genutzt
werden:
. . . to be continued . . .
117
sympy – ein Computer-Algebra-System
Sympy ist ein Modul, das ein Computer-Algebra-System für Python bereitstellt. Es kann,
wenn bei der Python-Installation das Paket python3-setuptools mit installiert wurde,
in einer Shell folgendermaßen heruntergeladen installiert werden:
Anschließend kann es beispielsweise mittels import sympy oder import sympy as sy im-
portiert werden. Im folgenden wird von letzterer Variante ausgegangen, um Schreibarbeit
zu sparen.
Im folgenden werden nur einige häufig vorkommende Funktionen von Sympy beschrieben.
Eine vollständige Dokumentation findet man auf der Sympy-Projektseite.
Ebenso sind in Sympy alle elementaren Funktionen wie sin(), cos(), exp() usw. definiert
und können in gleicher Weise wie im math-Modul verwendet werden. Weitere hilfreiche
Funktionen sind beispielsweise:
sy.Abs(x) Betragsfunktion
sy.binomial(n,k) Binomialkoeffizient
sy.factorial(num) Fakultät
sy.fibonacci(n) Fibonacci-Folge (𝑛-tes Element)
sy.log(x) Natürlicher Logarithmus (Basis 𝑒)
sy.log(x, a) Logarithmus zur Basis 𝑎
Das besondere an den Sympy-Funktionen ist, dass diese nicht nur eine einzelne Zahl
bzw. eine Variable als Argument akzeptieren, sondern auch auf so genannte „Symbole“
angewendet werden können. Mit diesem Datentyp werden in Sympy die in der Mathematik
für Variablennamen genutzten Buchstaben dargestellt. Beispielsweise kann eine in der
Mathematik typischerweise mit 𝑥 bezeichnete Variable folgendermaßen als Sympy-Symbol
definiert werden:
x = sy.S('x')
118
(Fortsetzung der vorherigen Seite)
type(x)
# Ergebnis: sympy.core.symbol.Symbol
Möchte man mehrere „Symbole“ – also mehrere „mathematische“ Variablen – auf einmal
definieren, so kann die symbols()-Funktion genutzt werden, um eine durch Leerzeichen
getrennte Zeichenkette als Liste von Symbol-Bezeichnungen zu interpretieren:
Bei der Festlegung von Symbolen mittels sy.S() oder sy.symbols() kann auch als Op-
tion positive=True angegeben werden, um nicht-negative mathematische Variablen zu
definieren.
Mit diesen Symbolen kann nun gerechnet werden, ohne ihnen einen expliziten Wert zu-
weisen zu müssen.
x = sy.S('x')
sy.expand( (x + 2)**5 )
# Ergebnis: x**5 + 10*x**4 + 40*x**3 + 80*x**2 + 80*x + 32
Die expand()-Funktion kann mittels der Optionen frac=True, log=True oder trig=True
auch zum Erweitern von Bruchtermen, Logarithmen oder trigonometrischen Ausdrücken
verwendet werden:
x = sy.S('x')
x1, x2 = sy.symbols('x1 x2')
Im letzten Beispiel wurde die Erweiterung durch die Option force=True erzwungen, da
Sympy in diesem Fall die angegebene Umformung des Terms als ungünstig einstuft.
119
x = sy.S('x')
x = sy.S('x')
x1, x2 = sy.symbols('x1 x2')
Weitere Vereinfachungen von Termen sind mit der Funktion simplify() möglich:
x = sy.S('x')
Die Funktion simpify() kann auch genutzt werden, um die Äquivalenz zweier Terme 𝑇1
und 𝑇2 zu überprüfen. Dies ist nicht zuletzt deshalb von Bedeutung, da die mathematische
Äquivalenz in Sympy nicht mit dem Vergleichsoperator als T1 == T2 geprüft werden kann.
Stattdessen kann aber geprüft werden, ob simplify(T1 - T2) den Wert Null ergibt:
sy.simplify(
sy.sin(x1 + x2) - ( sy.sin(x1) * sy.cos(x2) + sy.cos(x1) * sy.sin(x2) )
)
# Ergebnis: 0
Für trigonometrische Vereinfachungen kann zudem die Funktion trigsimp() genutzt wer-
den.
120
Gleichungen und Ungleichungen
Sympy kann insbesondere zum Lösen von Gleichungen, Gleichungssystemen und Unglei-
chungen genutzt werden. Eine Gleichung kann in Sympy folgendermaßen mittels der Funk-
tion Equation() beziehungsweise der Kurzform Eq() definiert werden:
x = sy.S('x')
Das Ergebnis von Eq() ist ein Gleichungs-Objekt. Dieses kann wahlweise in eine Variable
gespeichert oder an die Funktion solve() übergeben werden, um die Lösung(en) der
Gleichung zu bestimmen:
Gleichungen lassen sich auch mit mehreren Parametern 𝑎𝑖 formulieren, die bei Bedarf
mittels der Funktion subs() durch konkrete Werte ersetzt werden können:
x = sy.S('x')
a, b, c = sy.symbols("a b c")
sy.solve( eq, x )
# Ergebnis: (-b + sqrt(-4*a*c + b**2))/(2*a), -(b + sqrt(-4*a*c + b**2))/(2*a)]
equations = [
sy.Eq( 8*x1 + 2*x2 + 3*x3 , 15 ),
sy.Eq( 6*x1 - 1*x2 + 7*x3 , -13 ),
sy.Eq(-4*x1 + 5*x2 - 3*x3 , 21 ),
]
sy.solve(equations)
# Ergebnis: {x2: 4, x1: 2, x3: -3}
121
Zum Formulieren von Ungleichungen mit einer einzelnen Variablen zu formulieren, können
die folgenden Funktionen in gleicher Weise wie die Funktion Eq() genutzt werden:
𝑥2 − 8 · 𝑥 + 15 ≤ 2
Um die Ungleichung zu lösen, wird der obige Ausdruck wiederum an die Funktion solve()
übergeben:
. . . to be continued . . .
Links
Sympy Projektseite
Diese Sammlung an Übungsaufgaben und Lösungen (mit Quellcode) stellt eine in Python
3 geschriebene Version einer Vielzahl an ursprünglich für Maxima entwickelten Beispiel-
aufgaben dar (siehe Original-Quelle).
Ziffernsumme
Bei dieser Aufgabe handelt es sich um eine Knobelaufgabe bzw. um eine einfache Übungs-
aufgabe für lineare Gleichungssysteme.
damit mit einer reellen Zahl 𝑥 identisch, für die 𝑥 = Re(𝑧) gilt.
122
Aufgabe:
Die Aufgabe besteht darin, eine dreistellige Zahl zu finden, die folgende Bedingungen
erfüllt:
Lösung:
Definiert man die Variablen ℎ als die Hunderterziffer, 𝑧 als die Zehnerziffer und 𝑒 als die
Einerziffer, so ist die Ziffernsumme gleich 𝑧 + ℎ + 𝑒. Aus der Aufgabenstellung lassen sich
damit folgende drei Gleichungen aufstellen:
𝑧 + ℎ + 𝑒 = 18
ℎ−6=2·𝑧
𝑒−6=3·𝑧
Dieses Gleichungsystem kann mittels Sympy gelöst werden. Der Code dazu lautet bei-
spielsweise:
import sympy as sy
# Sympy-Variablen initiieren:
h, z, e = sy.S( 'h z e'.split() )
# Gleichungssystem formulieren:
equations = [
sy.Eq( z + h + e , 18 ),
sy.Eq( h - 6 , 2*z ),
sy.Eq( e - 6 , 3*z ),
]
# Gleichungssystem lösen:
sy.solve(equations)
# Ergebnis: {h: 8, z: 1, e: 9}
Die Hunderterziffer ist gleich 8, die Zehnerziffer gleich 1 und die Einerziffer gleich 9. Die
gesuchte Zahl lautet somit 819.
123
Zahlenrätsel (Division)
Bei dieser Aufgabe handelt es sich um eine Knobelaufgabe bzw. um eine einfache Übungs-
aufgabe für lineare Gleichungssysteme.
Aufgabe:
Die Problemstellung lautet eine Zahl 𝑥 zu finden, die, wenn sie durch (𝑥 − 𝑎) geteilt wird,
eine gegebene Zahl 𝑏 ergibt (𝑎 sei ebenfalls ein bekannter, konstanter Wert). Die Aufgabe
5
soll für 𝑎 = 10 und 𝑏 = 1 21 gelöst werden.
Lösung:
Es muss prinzipiell folgende Gleichung gelöst werden:
𝑥
=𝑏
𝑥−𝑎
5
Für 𝑎 = 10 und 𝑏 = 1 21 lautet die Gleichung konkret:
𝑥 5
=1
𝑥 − 10 21
Diese Gleichung kann bereits ohne weitere Vereinfachungen mittels Sympy gelöst werden.
Der Code dazu lautet folgendermaßen:
import sympy as sy
# Sympy-Variablen initiieren:
x = sy.S( 'x' )
a, b = sy.S( [10, 1+5/21] )
# Gleichung formulieren:
equation = sy.Eq( x/(x-a) , b )
# Gleichung lösen:
sy.solve(equation)
# Ergebnis: [52.0000000000000]
Aufgabe:
Das Volumen eines Rotationskörpers soll berechnet werden. Gegeben sind die erzeugende
Funktion, die Untergrenze und die Obergrenze des Intervalls. Die Rotation soll um die
𝑥-Achse erfolgen. Die Aufgabe soll für die Funktion 𝑓 (𝑥) = 𝑥2 + 𝑥 + 𝑥1 gelöst werden,
wobei die Untergrenze bei 𝑎 = 1 und die Obergrenze bei 𝑏 = 5 liegen soll.
124
Lösung:
Der Graph der Funktion 𝑓 (𝑥) = 𝑥2 + 𝑥 + 𝑥1 kann mit Hilfe von numpy und der matplotlib
geplottet werden:
# Wertereihen erzeugen:
x = np.arange(start=1,stop=5, step=0.01)
y = x**2 + x + 1/x
# Funktion plotten:
plt.plot(x,y)
# Layout anpassen:
plt.axis([0,6,0,35])
plt.xlabel("$x$")
plt.ylabel("$y$")
plt.grid(True)
plt.show()
1
Abb. 8: Graph der Funktion 𝑓 (𝑥) = 𝑥2 + 𝑥 + 𝑥
.
Um das Volumen des aus 𝑓 (𝑥) bei Rotation um die 𝑥-Achse entstehenden Rotionskör-
pers zu berechnen, kann man sich diesen aus lauter winzig schmalen (Zylinder-)Scheiben
zusammengesetzt denken. Jede dieser Scheiben hat als Radius den Wert 𝑓 (𝑥), als Höhe
2 2
den Wert d𝑥 und als Volumen somit 𝜋 · 𝑟 · ℎ = 𝜋 · 𝑓 (𝑥) · d𝑥. Alle diese infinitesimalen
Volumina müssen aufsummiert werden, was folgendem Integral entspricht:
∫︁ 𝑏 ∫︁ 5 (︂ )︂2
(︀ 2
)︀ 2 1
𝑉 = 𝜋 · 𝑓 (𝑥) · d𝑥 = 𝜋· 𝑥 +𝑥+ · d𝑥
𝑎 1 𝑥
125
Dieses Integral kann mittels Sympy berechnet werden. Der Code dazu lautet folgender-
maßen:
import sympy as sy
# Sympy-Variablen initiieren:
x = sy.S( 'x' )
a, b = sy.S( [1, 5] )
# Ergebnis: 15164*pi/15
# Ergebnis: 3175.94073326904
Geradliniger Flug
Bei dieser Aufgabe geht es darum, eine physikalische Bewegungsgleichung zu lösen.
Aufgabe:
Zwei Flugzeuge verlassen einen Flughafen zur selben Zeit in entgegengesetzte Richtungen
mit den Geschwindigkeiten 𝑣1 = 490 km/h beziehungsweise 𝑣2 = 368 km/h. Nach welcher
Zeit 𝑡 haben sie einen Abstand von 𝑠 = 3805 km erreicht?
Lösung:
Die beiden Flugzeuge bewegen sich mit der Summe ihrer Geschwindigkeiten, also mit
𝑣 = 𝑣1 + 𝑣2 = 858 km/h auseinander. Aus der Weg-Zeig-Formel 𝑠 = 𝑣 · 𝑡 für Bewegungen
mit konstanter Geschwindigkeit lässt sich die gesuchte Größe 𝑡 berechnen. Der Sympy -
Code dazu lautet:
import sympy as sy
# Sympy-Variablen initiieren:
s = sy.S( 3805 )
v = sy.S( 858 )
t = sy.S( 't' )
# Gleichung formulieren:
equation = sy.Eq( s , v * t )
# Gleichung lösen:
result = sy.solve(equation)
126
(Fortsetzung der vorherigen Seite)
# Ergebnis: [3805/858]
# Ergebnis: 4.434731934731935
Die gesuchte Zeit beträgt somit rund 4, 435 Stunden. Etwas eleganter ist allerdings die
Angabe in Stunden und Minuten. Sie kann aus dem obigen Ergebnis folgendermaßen
berechnet werden:
import math
result_f = float(result[0])
hours = math.floor(result_f)
# Ergebnis: 4.0
Leistungsaufgabe
Bei dieser Aufgabe handelt es sich um ein einfaches Dreisatzproblem.
Aufgabe:
Eine Anzahl von 𝑛1 = 8 Bauarbeitern, alle mit gleicher Leistung, benötigt 𝑡1 = 87 Ta-
ge, um ein Haus zu bauen. Wie viele Tage 𝑡2 sind zum Hausbau nötig, wenn 𝑛2 = 24
Bauarbeiter mit der selben Leistung daran arbeiten?
Lösung:
Diese Dreisatzaufgabe lässt sich als einfach Verhältnisgleichung darstellen. Da die insge-
samt benötigte Zeit als indirekt proportional zur Anzahl der Arbeiter angenommen wird,
𝑡 𝑛
ist das Verhältnis 1 der benötigen Zeiten gleich dem Verhältnis 2 der Arbeiterzahlen:
𝑡2 𝑛1
𝑡1 𝑛1
=
𝑡2 𝑛2
Diese Gleichung lässt sich auch ohne Computer-Algebra-System leicht nach 𝑡2 auflösen
(insbesondere, wenn man auf beiden Seiten die Kehrwerte bildet, d.h. die Gleichung
𝑡2
𝑡1
= 𝑛𝑛12 betrachtet). Dennoch soll an dieser Stelle die Aufgabe als Beispiel für vielfach
vorkommende Dreisatzaufgaben mit Sympy gelöst werden:
import sympy as sy
127
(Fortsetzung der vorherigen Seite)
# Sympy-Variablen initiieren:
n1, n2 = sy.S( [8, 24] )
t1 = sy.S( 87 )
t2 = sy.S( 't2' )
# Gleichung formulieren:
equation = sy.Eq( t1/t2 , n2/n1 )
# Gleichung lösen:
result = sy.solve(equation)
# Ergebnis: [29]
Aufgabe:
Betrachtet wird eine Folge 𝑥n von aufeinander folgenden, ganzzahligen Werten (𝑥, 𝑛 ∈ N).
∑︀𝑚1
∑︀𝑛 𝑖=1 𝑥i der ersten 𝑚1 Zahlen sei um einen Differenzwert 𝑑 kleiner als die
Die Summe
Summe 𝑖=𝑚1 +1 𝑥i der restlichen Zahlen. Wie lässt sich diese Aufgabe mathematisch
formulieren? Welche Lösung ergibt sich für 𝑛 = 5, 𝑚1 = 2 und 𝑑 = 42?
Lösung:
Damit die obige Bedingung erfüllt ist, muss folgende Gleichung gelten:
𝑚1
∑︁ 𝑛
∑︁
(𝑥𝑖 ) + 𝑑 = (𝑥𝑖 )
𝑖=1 𝑖=𝑚1 +1
Um diese Aufgabe mit sympy zu lösen, können beide Summen in der obigen Gleichung
auch in folgender Form dargestellt werden:
𝑚1
∑︁ 𝑛
∑︁
(𝑥 + 𝑖) + 𝑑 = (𝑥 + 𝑖)
𝑖=1 𝑖=𝑚1 +1
Hierbei ist der zu bestimmende Initialwert 𝑥 um 1 kleiner als der erste Wert der Zah-
lenreihe. Diese Darstellung hat den Vorteil, dass die Summen leichter formuliert werden
können und die Gleichung nur noch eine Unbekannte aufweist. Der Quellcode zur Lösung
der Gleichung mittels Sympy kann beispielsweise so aussehen:
import sympy as sy
# Sympy-Variablen initiieren:
n,m1,d = sy.symbols('n m1 d')
(continues on next page)
128
(Fortsetzung der vorherigen Seite)
# Terme festlegen
s1 = sy.summation(x + i, (i,1,m1))
s2 = sy.summation(x + i, (i,m1+1,n))
# Gleichungen formulieren:
equation = sy.Eq( s1 + d , s2)
equation_concrete = equation.subs({n:5,m1:2,d:42})
# Gleichung(en) lösen:
sy.solve(equation, x, 'dict')
sy.solve(equation_concrete, x, 'dict')
# Ergebnisse:
# Allgemein:
# [{x: (-d - m1**2 - m1 + n**2/2 + n/2)/(2*m1 - n)}]
# Konkret:
# [{x:33}]
Beim Lösen der Gleichung wurde hierbei explizit die Variable 𝑥 als gesuchte Variable an-
gegeben; ebenso könnte die Gleichung beispielsweise nach 𝑑 für einen gegebenen Startwert
𝑥 aufgelöst werden.
Das Ergebnis für die konkrete Aufgabe lautet 𝑥 = 33. In diesem Fall sind die 𝑛 = 5 Zahlen
also gleich (34, 35, 36, 37, 38), die Summe der ersten 𝑚1 = 2 Zahlen ist 𝑠1 = 34 + 35 = 69,
die Summe der weiteren Zahlen ist gleich 36 + 37 + 38 = 111.
Altersaufgabe
Bei dieser Aufgabe geht es um die Formulierung und das Lösung einer Funktionsgleichung.
Aufgabe:
Wenn K. heute 𝑚=3 mal so alt wäre wie vor 𝑛=6 Jahren, dann wäre K. nun 𝑗 = 38
Jahre älter. Wie alt ist K. heute?
Lösung:
Die gesuchte Variable 𝑥 gebe das heutige Alter von K. an. Dann lässt sich aus den obigen
Bedingungen folgende Gleichung aufstellen:
𝑚 * (𝑥 − 𝑛) = 𝑥 + 𝑗
import sympy as sy
129
(Fortsetzung der vorherigen Seite)
# Sympy-Variablen initiieren:
x = sy.S( 'x' )
m,n,j = sy.S([3, 6, 38] )
# Gleichung formulieren:
equation = sy.Eq( m * (x-n) , x + j )
# Gleichung lösen:
sy.solve(equation)
# Ergebnis: [28]
Diskriminante
Bei dieser Aufgabe geht es darum, die Diskriminante einer quadratischen Gleichung zu
bestimmen.
Aufgabe:
Gegeben sei die quadratische Gleichung 𝑓 (𝑥) = 𝑥2 −8·𝑥−15. Wie lautet die Diskriminante
dieser Gleichung?
Lösung:
Die Diskriminante 𝐷 einer quadratischen Gleichung 𝑓 (𝑥) = 𝑎 · 𝑥2 + 𝑏 · 𝑥 + 𝑐 lässt sich in
Abhängigkeit der Parameter 𝑎, 𝑏 und 𝑐 folgendermaßen bestimmen:
𝐷 = 𝑏2 − 4 · 𝑎 · 𝑐
import sympy as sy
# Sympy-Variable initiieren:
x = sy.S( 'x' )
# Gleichung formulieren:
f = x**2 - 8*x - 15
a = f.coeff(x, n=2)
b = f.coeff(x, n=1)
c = f.coeff(x, n=0)
D = b**2 - 4*a*c
# Ergebnis: 124
130
√
−𝑏± 𝐷
Die Diskriminante ist positiv, somit hat die Gleichung die zwei Lösungen 𝑥1,2 = 2·𝑎
:
x1 = ( -b + sy.sqrt(D) ) / (2 * a)
x2 = ( -b - sy.sqrt(D) ) / (2 * a)
x1.evalf()
# Ergebnis: 9.56776436283002
x2.evalf()
# Ergebnis: -1.56776436283002
Der Funktionsgraph als Ganzes kann mittels numpy und matplotlib folgendermaßen er-
zeugt werden:
# Wertereihen erzeugen:
x = np.arange(-3,11,0.01)
y = x**2 - 8*x - 15
# Funktion plotten:
plt.plot(x,y)
# Layout anpassen:
plt.axis([-3,11,-35,35])
plt.xlabel("$x$")
plt.ylabel("$y$")
plt.grid(True)
plt.show()
Aufgabe:
√
Gegeben ist die Diagonale 𝑑=3· 2 eines Quadrats. Wie lässt sich daraus die Fläche 𝐴
des Quadrats berechnen?
Lösung:
Allgemein gilt für die Diagonale 𝑑 eines Quadrats in Abhängigkeit von der Seitenlänge 𝑎:
√
𝑑= 2·𝑎
131
Abb. 9: Graph der Funktion 𝑓 (𝑥) = 𝑥2 − 8 · 𝑥 − 15.
Somit lässt sich aus 𝑑 die Seitenlänge 𝑎 und damit die Fläche 𝐴 = 𝑎2 des Quadrats
berechnen. Ein Beispielcode mit Sympy kann beispielsweise so aussehen:
import sympy as sy
# Sympy-Variablen initiieren:
d = sy.S( 3 * sy.sqrt(2) )
a = sy.S( 'a' )
# Seitenlänge berechnen:
a = d / sy.sqrt(2)
# Fläche berechnen:
A = a**2
# Ergebnis: 9
Aufgabe:
Gegeben ist die Liste [(3,4,5), (10,8,6), (25,21,12)], deren Einträge jeweils die
Maße eines Quaders angeben (Länge, Breite und Höhe). Berechne das Volumen sowie die
Oberfläche der einzelnen Quader.
132
Lösung:
Das Volumen eines Quaders ist gleich dem Produkt aus Länge 𝑙, Breite 𝑏 und Höhe ℎ;
seine Oberfläche ist gleich der doppelten Summe aller Flächen, die sich aus je zwei der
drei Größenangaben berechnen lassen:
𝑉Quader = ℎ · 𝑏 · 𝑙
𝐴Quader = 2 · (ℎ · 𝑏 + 𝑏 · 𝑙 + 𝑙 · ℎ)
In Python können die gesuchten Größen (auch ohne sympy) beispielsweise durch Definition
von geeigneten Funktionen berechnet werden:
# Variablen initiieren:
cuboid_dimensions = [(3,4,5), (10,8,6), (25,21,12)]
cuboid_surfaces = []
cuboid_volumes = []
# Funktionen definieren:
def get_cuboid_surface(length, width, height):
""" Calculate the surface of a cuboid."""
cuboid_surfaces.append( get_cuboid_surface(*c) )
cuboid_volumes.append( get_cuboid_volume(*c) )
# Ergebnis:
In der Hauptschleife werden beide Funktionen für die jeweiligen Größenangaben aufgeru-
fen; die Hilfsvariable c wird dabei, da es sich um ein um eine Sequenz handelt, mit einem
davor stehenden * an die Funktion übergeben. Dies bewirkt, dass nicht das Zahlentripel
als eigenes Objekt verwendet wird, sondern vielmehr dessen Inhalte „ausgepackt“ und der
Reihenfolge nach an die Funktion übergeben werden.
133
Aufgabe:
Gegeben ist folgende Liste an Quadergrößen (Länge, Breite, Höhe):
[(3,4,5),(6,8,10),(1,2,4),(12,13,32), (14,8,22),(17,3,44),(12,5,3),(10,9,11)]
Bestimme das Minumum und Maximum der Quadervolumina, die sich anhand der obigen
Längenmaße ergeben.
Lösung:
Das Volumen der einzelnen Quader lässt sich als Produkt der drei Längenangaben be-
rechnen:
𝑉Quader = 𝑙 · 𝑏 · ℎ
# Variablen initiieren:
cuboid_dimensions = [(3,4,5), (6,8,10), (1,2,4), (12,13,32), (14,8,22),
(17,3,44), (12,5,3), (10,9,11)
]
# Volumina berechnen:
cuboid_volumina = [ l * b * h for l,b,h in cuboid_dimensions]
Zur Erstellung der Volumina-Liste wurden hierbei eine so genannte List Comprehensi-
on genutzt. Möchte man wissen, welches Listenelement zum Wert des minimalen bzw.
maximalen Volumens gehört, so kann man die Listen-Index-Funktion nutzen:
# Ergebnis: 2 bzw. 3
Python beginnt mit der Indizierung von Listenelementen bei Null, so dass die Ergebnis-
werte dem dritten und vierten Listenelement entsprechen.
Quader
Bei dieser einfachen Aufgabe soll anhand der Länge, Breite und Höhe eines Quaders dessen
Volumen, Oberfläche und Raumdiagonale bestimmt werden.
Aufgabe:
Bestimme zu den Massen 𝑙 = 10, 𝑏 = 8 und 𝑐=6 das Volumen, die Oberfläche und die
Raumdiagonale eines Quaders.
134
Lösung:
Die gesuchten Größen lassen sich folgendermaßen berechnen:
𝑉Quader = ℎ · 𝑏 · 𝑙
𝐴Quader = 2 · (ℎ · 𝑏 + 𝑏 · 𝑙 + 𝑙 · ℎ)
√
𝑑Quader = 𝑙2 + 𝑏2 + ℎ2
Die rechte Seite der letzten Gleichung entspricht dem Betrag eines dreidimensionalen
Vektors.
Zur Berechnung der Quaderdiagonale kann die Funktion sqrt() aus dem math-Modul
genutzt werden:
import math as m
import functools as ft
cuboid_dimensions = [10,8,6]
cuboid_surface = lambda
cuboid_surface = 2 * (
cuboid_dimensions[0] * cuboid_dimensions[1] +
cuboid_dimensions[0] * cuboid_dimensions[2] +
cuboid_dimensions[1] * cuboid_dimensions[2]
)
cuboid_diagonal = m.sqrt(
cuboid_dimensions[0]**2 +
cuboid_dimensions[1]**2 +
cuboid_dimensions[2]**2
)
# Ergebnisse:
# cuboid_volume: 480
# cuboid_surface: 376
# cuboid_diagonal: 14.142135623730951
Bei der Berechnung des Quadervolumens wurde, um Schreibarbeit zu sparen, die Funktion
reduce() aus dem functools -Modul verwendet.
Anstelle des Lambda-Ausdrucks (quasi einer Funktion ohne Namen) kann auch die Funk-
tion mul() aus dem Modul operator verwendet werden. Diese wertet das Produkt aller
Werte einer (als eingigem Argument übergebenen) Liste aus:
import operator as op
# Ergebnis: True
135
Zudem könnte die Schreibarbeit durch die Definition von Funktionen entsprechend Auf-
gabe Quaderliste – Volumen und Oberfläche weiter reduziert werden.
Punktspiegelung
Bei sollen für einem gegebenen Punkt die Koordinaten eines neuen Punktes bestimmt
werden, der sich durch Spiegelung an der 𝑥- oder 𝑦 -Achse ergibt.
Aufgabe:
Eine bestimmter Punkt P soll entweder um die 𝑥- oder 𝑦 -Achse gespiegelt werden. Die
Koordinaten des Punktes sowie die Wahl der Spiegelungsachse sollen durch den Benutzer
eingegeben werden.
Lösung:
Die Koordinaten des gespiegelten Punkts lassen sich einfach berechnen, indem die jeweilige
Koordinate mit (-1) multipliziert wird.
Um eine Eingabe von einem Benutzer zu erhalten, kann in Python die input()-Funktion
genutzt werden, welche die eigegebene Textzeile als String-Variable speichert. Diese wird
im folgenden Beispiels schrittweise überarbeitet, indem zunächst mögliche runde Klam-
mern mit der String-Funktion strip entfernt werden, der String anschließend am Kom-
mazeichen in eine Liste zweier Strings zerlegt wird, und zuletzt eine neue Liste mittels
einer List Comprehension anhand der Elemente der bestehenden Liste erstellt wird. Dieser
Schritt ist notwendig, um aus den als Strings gespeicherten Zahlenwerten Float-Variablen
zu erzeugen.
new_point = []
if axis == 'x':
if axis == 'y':
new_point.append( opoint[0] )
new_point.append( opoint[1] * (-1) )
136
Der obige Code zeigt nur die grundlegende Logik auf. In einem „richtigen“ Programm sollte
die Eingabe nach falscher Syntax hin untersucht und gegebenenfalls ein entsprechendes
Exception-Handling vorgenommen werden.
Aufgabe :
Der Scheitel einer Parabel ist zu bestimmen. Es ist zu entscheiden, ob die Parabel nach
unten oder nach oben geöffnet ist.
Lösung:
Die Orientierung einer Parabel kann man am Koeffizienten ihres quadratischen Terms
ablesen; ist dieser positiv, so ist die Parabel nach oben, andernfalls nach unten geöffnet.
Der Scheitelpunkt ist das einzige Extremum einer Parabel. Um ihn zu bestimmen, bildet
man daher die erste Ableitung der quadratischen Funktion und setzt diese gleich Null. So
erhält man den 𝑥-Wert des Scheitelpunktes. Den zugehörigen 𝑦 -Wert erhält man, indem
man den 𝑥-Wert des Scheitelpunktes in die ursprüngliche Funktionsgleichung einsetzt.
import sympy as sy
137
(Fortsetzung der vorherigen Seite)
print("Die Orientierung der Parabel ist \"%s \", ihr Scheitel liegt bei \
(%.2f , %.2f )." % (orientation, x_0, y_0) )
Aufgabe:
Für eine Kreis- und eine Geradengleichung ist die Lagebeziehung (Sekante, Tangente,
Passante) der beiden geometrischen Objekte zueinander zu bestimmen.
Lösung:
Wenn eine Gerade einen Kreis in zwei Punkten schneidet, dann ist die Gerade eine
Sekante.
Wenn eine Gerade einen Kreis in einem Punkt berührt, dann ist die Gerade eine
Tangente.
Wenn die Gerade und der Kreis keinen Punkt gemeinsam haben, dann ist die Gerade
eine Passante.
import sympy as sy
# Gleichungssystem lösen
solutions = sy.solve(equations)
138
(Fortsetzung der vorherigen Seite)
if len(solutions) == 2:
print("Die Gerade ist eine Sekante.")
elif len(solutions) == 1:
print("Die Gerade ist eine Tangente.")
else:
print("Die Gerade ist eine Passante.")
Beim Erstellen des Gleichungssystems wurde bei der Übergabe der einzelnen Sympy-
Elemente der Stern-Operator * vorangestellt, um nicht die Liste, sondern deren Inhalt an
die Eq()-Funktion zu übergeben.
139
Bottle – Ein Mikro-Framework für
interaktive Webseiten
Das bottle-Modul bietet eine einfache Möglichkeit zum schnellen Erstellen von WSGI-
basierten Webseiten („Web Server Gateway Interface“). Die eigentliche Anwendung kann
dabei aus einer einzigen Datei bestehen.
Alternativ hierzu kann man bottle auch, sofern man das Paket python3-setuptools via
aptitude pip3 install bottle installieren.
installiert hat, mittels
Um mittels Bottle eine einfache Webanwendung zu programmieren, genügt es, das gleich-
namige bottle-Paket oder einzelne Funktionen daraus in eine Python-Datei zu importie-
ren. Ein einfaches Code-Beispiel sieht somit etwa folgendermaßen aus:
#!/usr/bin/env python3
@route('/hallo/<name>')
def hallo(name):
return 'Hallo {0}!'.format(name)
debug(True)
run()
Speichert man dieses Programm beispielsweise als Datei hallo-welt.py und ruft es aus
einer Shell heraus mittels python3 hallo-welt.py auf, so kann man sich das Ergebnis
im Webbrowser unter der Adresse http://localhost:8080/hallo/Welt anzeigen las-
sen. Gibt man in diesem Pfad einen anderen Namen als „Welt“ an, so bekommt man im
Webbrowser eine entsprechend andere Begrüßung angezeigt.
Die Funktionsweise der Bottle-Anwendung liegt darin, einen Browserpfad über die
route()-Funktion mit einer gewöhnlichen Python-Funktion zu verbinden. Über die
140
return-Anweisung kann wahlweise ein einfacher Text im Browser ausgegeben oder auch
eine andere Funktion aufgerufen werden, die dann beispielsweise ein HTML-Template
rendert und mit Text füllt.
Die run()-Funktion startet den von Bottle ohne weitere Abhängigkeiten bereitgestell-
ten WSGI-Server mit dem üblichen HTML-Standard-Port 8080; man kann auch mittels
beispielsweise run(port=8081) einen anderen Localhost-Port vorgeben. Ruft man die
Funktion run() mit der Option reloader=True auf, so werden Änderungen unmittelbar,
also auch ohne Neustart des WSGI-Servers übernommen.
HTML-Templates
Möchte man nicht nur reinen Text im Webbrowser anzeigen, sondern eine Ausgabe
in HTML-Form erreichen, so kann wahlweise die im bottle-Modul bereits integrierte
SimpleTemplate-Engine genutzt werden; als Alternative dazu können auch Jinja2, ‘ oder
Mako eingesetzt werden, welche mittels pip3 und den gleichen Paketnamen nachinstalliert
werden können (pip3 install Jinja2).
. . . to be continued . . .
https://www.fullstackpython.com/wsgi-servers.html
Links:
141
Kivy - ein Toolkit für GUI-Programme
Kivy ist eines von mehreren Toolkits, mit denen sich in Python Programme mit einer gra-
1
phischen Bedienoberfläche (Graphical User Interface, kurz: GUI) programmieren lassen.
Um Kivy mit Python3 nutzen zu können, müssen die folgenden Pakete installiert werden:
# Kivy-Pakete installieren:
sudo aptitude install cython3 python3-kivy python3-kivy-bin python3-kivy-common
Mit Kivy geschriebene Programme haben stets eine App-Klasse, die am einfachsten mit-
tels Vererbung auf der Standard-App-Klasse aufbauen kann. Diese Standard-Klasse stellt
unter anderem eine run()- und eine build()-Methode bereit, wobei letztere automa-
tisch aufgerufen wird, wenn das Programm mittels der run()-Methode gestartet wird.
Die build()-Funktion wiederum startet automatisch das graphische Bedienfenster, und
kann zugleich weitere Elemente in diesem Fenster platzieren; sie sollte als Ergebnis stets
das „Root“-Widget der Anwendung liefern.
Im einfachsten Fall soll ein schlichter „Button“ mittig im Fenster platziert werden, der
die Bezeichnung „Hallo Welt!“ trägt. Ein erstes vollständiges Programm, das wiederum
auf ein bereits vordefiniertes Button-Element zurückgreift, kann damit folgendermaßen
aussehen:
1 Weiter GUI-Toolkits für Python sind das in der Standard-Installation enthaltene Tkinter, sowie
PyGTK, PyQT und wxPython (siehe Übersicht). Kivy ist allerdings das einzige in Python selbst ge-
142
# Datei: hello.py
import kivy
kivy.require('1.9.0') # Mindest-Version von Kivy
class HelloApp(App):
def build(self):
return Button(text='Hallo Welt!')
if __name__== "__main__":
HelloApp().run()
Das uix-Modul stellt allgemeine GUI-Elemte bereit, wie beispielsweise Widgets und Lay-
outs.
Bei einem Aufruf der Programmdatei wird durch die if-main-Abfrage eine Instanz der
App erzeugt und diese gestartet, wobei wiederum die build()-Funktion aufgerufen wird:
python3 hello.py
Dieses erste Programm hat keine weitere Funktion; es kann beendet werden, indem auf
das X-Symbol geklickt wird oder in der Shell die Anwendung mittels Ctrl c unterbrochen
wird.
Das Layout einer Anwendung sollte für eine bessere Übersichtlichkeit, Anpassungsfähig-
keit und Wiederverwertbarkeit von der eigentlichen „Logik“ des Programms getrennt sein
(„Model-View-Controller“). Mit Kivy wird dieser Grundsatz in einer Art und Weise ver-
folgt, der stark an die Anpassung des Layouts einer Webseite mittels CSS erinnert: Das
143
Aussehen der einzelnen graphischen Elemente eines Programms wird über eine entspre-
chende .kv-Datei festgelegt werden.
Beim Aufruf der Programm-Datei wird automatisch diejenige .kv-Datei im gleichen Ver-
zeichnis geladen, deren Namen mit (in Kleinbuchstaben) dem Namen der App-Klasse
übereinstimmt: Hat die App-Klasse beispielsweise den Namen HelloWorldApp, so heißt
die zugehörige .kv-Datei helloworld.kv. In dieser Datei kann mit einer YAML-artigen
Syntax das Design einzelner „Widgets“ (Teilbereiche des Hauptfensters) sowie deren An-
ordnung festgelegt werden.
. . . to be continued . . .
Links
144
Anhang
Schlüsselwörter
Die in der obigen Tabelle angegebenen Wörter können nicht als Variablen- oder Funkti-
onsnamen verwendet werden. Mittels der Funktion iskeyword() aus dem Modul keyword
kann getestet werden, ob eine Zeichenkette ein Schlüsselwort ist:
iskeyword("lambda")
# Ergebnis: True
Standardfunktionen
abs()
Die Funktion abs(x) gibt den Absolutwert einer Zahl x als Ergebnis zurück.
Beispiel:
abs( -5.7 )
# Ergebnis: 5.7
abs( +5.7 )
# Ergebnis: 5.7
145
all()
Die Funktion all(sequenz) kann auf ein beliebiges iterierbares Objekt (Listen oder Men-
gen) angewendet werden. Als Ergebnis wird True zurückgegeben, wenn alle Elemente den
Wahrheitswert True besitzen; andernfalls wird False als Ergebnis zurückgegeben.
Beispiel:
all( [1,3,5,0,7] )
# Ergebnis: False
all( [3,7,9,5,2] )
# Ergebnis: True
any()
Die Funktion any(sequenz) kann auf ein beliebiges iterierbares Objekt (Listen oder Men-
gen) angewendet werden. Als Ergebnis wird True zurückgegeben, wenn zumindest ein
Element den Wahrheitswert True besitzt; andernfalls wird False als Ergebnis zurückge-
geben.
Beispiel:
any( [0,0,0,0,0] )
# Ergebnis: False
any( [0,0,0,1,0] )
# Ergebnis: True
ascii()
Die Funktion ascii(objekt) gibt ebenso wie die Funktion repr() als Ergebnis eine Zeichen-
kette zurück, die eine kurze charakteristische Beschreibung des Objekts beinhaltet; häufig
entspricht dies einer Angabe der Objekt-Klasse, des Objekt-Namens und der Speicher-
adresse.
Beispiel:
ascii(print)
# Ergebnis: '<built-in function print>'
Ist in der Klasse des angegebenen Objekts eine __repr__()-Methode definiert, so ist
repr(objekt) identisch mit objekt.__repr__(). Als Zeichensatz wird für die Ausgabe
des Strings allerdings der ASCII-Zeichensatz verwendet, so dass darin nicht enthaltene
Symbole durch Zeichen mit vorangestelltem \x, \u oder \U gekennzeichnet werden.
146
bin()
Die Funktion bin(x) gibt eine Zeichenkette mit der Binärdarstellung einer einer Integer-
Zahl als Ergebnis zurück. Eine solche Zeichenkette wird mit 0b eingeleitet, gefolgt von
der eigentlichen Binärzahl.
Beispiel:
bin(42)
# Ergebnis: '0b101010'
bool()
Die Funktion bool(ausdruck) gibt den Wahrheitswert eines logischen Ausdrucks an;
dieser kann entweder True oder False sein. Als Argument kann entweder ein mittels
:ref‘Vergleichsoperatoren <Operatoren>‘ erzeugter logischer Ausdruck oder auch ein ein-
zelnes Objekt übergeben werden.
Listen, Tupel und Zeichenketten haben den Wahrheitswert True, wenn sie nicht leer
sind beziehungsweise mindestens ein Zeichen enthalten.
Zahlen haben dann den Wahrheitswert True, wenn sie nicht gleich Null sind.
bool(-3)
# Ergebnis: True
callable()
Die Funktion callable(objekt) gibt in Form eines booleschen Wahrheitswertes an, ob das
als Argument übergebene Objekt (wie eine Funktion oder Methode) aufrufbar ist oder
nicht.
Beispiel:
callable(5)
# Ergebnis: False
callable(print)
# Ergebnis: True
chr()
Die Funktion chr(zahl) gibt zu einem angegebenen Ganzzahl-Wert mit positivem Vorzei-
chen das entsprechende Unicode-Zeichen aus.
147
Beispiel:
chr(65)
# Ergebnis: 'A'
chr(97)
# Ergebnis: 'a'
Für viele Programme reichen die ASCII-Codes als Teilmenge des Unicode-Zeichensatzes
bereits aus.
classmethod()
Die Funktion classmethod(methode) macht die angegebene Methode zu einer so genannten
Klassen-Methode. Üblicherweise wird die classmethod()-Funktion als Funktionsdekora-
tor verwendet:
class C():
@classmethod
def my_class_method(cls, arguments):
pass
Bei einer so definierten Methode wird die als erstes Argument der Name der Klasse angege-
ben, von der aus die Methode aufgerufen wird. Die Klassen-Methode des obigen Beispiels
kann dann wahlweise mittels C.my_class_method() oder ausgehend von einer Instanz der
Klasse, also mittels C().my_class_method() aufgerufen werden; im letzteren Fall wird
beim Aufruf nur der Name der Instanzklasse, nicht die Instanz selbst als erstes Argument
an die Methode übergeben.
Wird eine Klassen-Methode von einer Instanz einer Klasse aufgerufen, welche die Methode
lediglich über eine Vererbung erhalten hat, so wird beim Aufruf dennoch der Name der
konkreten Instanzklasse (und nicht der Basis-Klasse) übergeben.
compile()
Die Funktion compile(code, file, mode) übersetzt den als erstes Argument angegebenen
Code-String in ein ausführbares, in Maschinensprache geschriebenes Bytecode-Objekt.
Als zweites Argument muss der Pfad einer Datei angegeben werden, in die gegebenenfalls
auftretende Fehler geschrieben werden sollen. Als drittes Argument muss entweder zum
Kompilieren genutzte Modus angegeben werden:
single, wenn es sich bei dem angegebenen Code um eine einzelne Aussage-
Komponente (beispielsweise den Wert einer Variablen) handelt;
exec, wenn der angegebene Code aus einer oder mehreren Aussagen besteht und als
Ergebnis None liefern soll.
148
Der compilierte Bytecode kann anschließend mittels eval() beziehungsweise exec() ausge-
führt werden.
Beispiel:
# Bytecode erzeugen:
a = 5
# Bytecode ausführen:
complex()
Die Funktion complex() erstellt eine neue Instanz einer komplexen Zahl aus zwei angege-
benen Zahlen oder einem angegebenen String.
Beispiel:
complex(1.5, 2)
# Ergebnis: (1.5+2j)
Wird ein String als Argument angegeben, so muss darauf geachtet werden, dass kein Leer-
zeichen zwischen dem Realteil, dem Pluszeichen und dem Imaginärteil steht; complex()
löst sonst einen ValueError aus.
149
delattr()
Die Funktion delattr(objekt, attributname) löscht ein angegebenes Attribut beziehungs-
weise einen angegebenen Funktionsnamen (eine Zeichenkette) aus dem als erstes Argu-
ment angegebenen Objekt; dies ist formal identisch mit del objekt.attributname.
import math as m
# Attribut löschen:
delattr(m, 'cos')
# Test:
m.cos( m.pi/4 )
# Ergebnis: 'module' object has no attribute 'cos'
dict()
Die Funktion dict() erzeugt eine neue Instanz eines dict -Objekts, also ein Dictionary.
Formal ist d = dict() somit identisch mit d = {}.
Beispiel:
# Schlüssel-Wert-Paar hinzufügen:
d['test'] = 'Hallo Welt!'
d
# Ergebnis: {'test': 'Hallo Welt!'}
dir()
Die Funktion dir() gibt, wenn sie ohne ein angegebenes Argument aufgerufen wird, eine
Liste mit den Namen aller in der aktuellen Python-Sitzung definierten Objekt-Namen (als
Strings) zurück.
Wird als Argument ein beliebiges Objekt angegeben, so werden die Attribute und Metho-
den des jeweiligen Objekts in Form einer String-Liste ausgegeben.
Beispiel:
import math as m
dir(m)
# Ergebnis:
# ['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos',
# 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign',
(continues on next page)
150
(Fortsetzung der vorherigen Seite)
divmod()
Die Funktion divmod(zahl1, zahl2) dividiert die als erstes Argument angegebene Zahl
durch die zweite Zahl. Als Ergebnis gibt die Funktion ein Tupel zweier Werte zurück,
wobei der erste Wert das ganzzahlige Ergebnis der Division und der zweite Wert den
Divisionsrest angibt.
Beispiel:
divmod(14,5)
# Ergebnis: (2, 4)
enumerate()
Die Funktion enumerate(sequenz) ermöglicht es, die Einträge einer Liste oder eines Tupels
zu nummerieren. Damit lassen sich beispielsweise for-Schleifen über die Elemente einer
Liste konstruieren, in denen beide Informationen verwendet werden.
Beispiel:
liste = [5, 6, 7, 8, 9]
# Ergebnis:
# Der 0. Eintrag in der Liste ist 5
# Der 1. Eintrag in der Liste ist 6
# Der 2. Eintrag in der Liste ist 7
# Der 3. Eintrag in der Liste ist 8
# Der 4. Eintrag in der Liste ist 9
eval()
Die Funktion eval(zeichenkette) erstellt aus der angegebenen Zeichenkette den entspre-
chenden Python-Ausdruck und wertet diesen aus; es darf sich dabei allerdings nur um
einen einzelnen Ausdruck, nicht um ein aus vielen einzelnen Aussagen zusammengesetz-
tes Code-Stück handeln.
Der Rückgabewert von eval() entspricht dabei dem Ergebnis des ausgewerteten Aus-
drucks.
151
Beispiel:
x = 1
eval('x+1')
# Rückgabewert / Ergebnis: 2
Die Funktion eval() kann ebenso verwendet werden, um einen mittels compile() er-
zeugten Ausdruck auszuwerten. Wurde als Compilier-Modus hierbei 'single' oder eval
angegeben, so entspricht der Rückgabewert wiederum dem Ergebnis des Ausdrucks; bei
der Angabe von exec() als Compilier-Modus liefert eval() als Ergebnis stets den Wert
None.
exec()
Die Funktion exec(zeichenkette) führt – ähnlich wie eval() – einen (beispielsweise mittels
compile() konstruierten) Python-Ausdruck aus; es kann sich dabei auch um eine beliebig
lange Zusammensetzung einzelner Python-Ausdrücke handeln. Als Ergebnis wird stets
None zurückgegeben.
Beispiel:
exec('print("Hallo Welt!")')
# Rückgabewert: None
# Ergebnis (Auf dem Bildschirm):
# Hallo Welt!
exec('42')
# Rückgabewert / Ergebnis: None
Die Funktion exec() kann ebenso verwendet werden, um einen mittels compile() er-
zeugten Ausdruck auszuwerten; auch hierbei ist der Rückgabewert stets None.
152
filter()
Die Funktion filter(funktionsname, objekt) bietet die Möglichkeit, eine Filter-Funktion
auf alle Elemente eines iterierbaren Objekts (beispielsweise einer Liste) anzuwenden. Als
Ergebnis gibt die filter()-Funktion ein iterierbares Objekt zurück. Dieses kann beispiels-
weise für eine for-Schleife genutzt oder mittels list() in eine neue Liste umgewandelt
werden.
Beispiel:
my_list = [1,2,3,4,5,6,7,8,9]
list(even_numbers)
# Ergebnis: [2,4,6,8]
Oftmals kann anstelle derfilter()-Funktion allerdings auch eine (meist besser les-
bare) List-Comprehension genutzt werden. Im obigen Beispiel könnte auch kürzer
even_numbers = [x for x in my_list if x % 2 == 0] geschrieben werden.
float()
Die Funktion float() gibt, sofern möglich, die zur angegebenen Zeichenkette oder Zahl pas-
sende Gleitkomma-Zahl als Ergebnis zurück; wird eine int-Zahl als Argument übergeben,
so wird die Nachkommastelle .0 ergänzt.
Beispiel:
float(5)
# Ergebnis: 5.0
float('3.2')
# Ergebnis: 3.2
float('1e3')
# Ergebnis: 1000.0
format()
Die Funktion format(wert, formatangabe) formatiert die Ausgabe des angegebenen Werts.
Hierzu können als Format-Angabe die für die Formatierung von Zeichenketten üblichen
Symbole verwendet werden. Wird kein Format angegeben, so wird die in der Objektklasse
des Werts definierte Funktion wertklasse.__format__() aufgerufen.
Beispiel:
153
# Zeichenkette zentriert ausgeben (Gesamtbreite 20):
format('Hallo Welt!', '^20')
# Ergebnis: ' Hallo Welt! '
frozenset()
Die Funktion frozenset(sequenz) erzeugt aus der angegebenen Sequenz (beispielsweise
einer Liste oder einer Zeichenkette) eine neue Instanz eines frozenset -Objekts, also eine
unveränderliche Menge.
Beispiel:
frozenset( [1, 3, 5, 7, 9, 9] )
# Ergebnis: frozenset({1, 3, 5, 7, 9})
getattr()
Die Funktion getattr(objekt, attributname) gibt als Ergebnis den Wert von objekt.
attributname zurück. Als drittes Argument kann optional ein Standard-Wert angege-
ben werden, der als Ergebnis zurück gegeben wird, wenn das angegebene Attribut nicht
existiert.
Beispiel:
# Beispiel-Klasse:
class Point():
x = 5
y = 4
# Punkt-Objekt erzeugen:
p = Point()
getattr(p, 'x')
# Ergebnis: 5
154
(Fortsetzung der vorherigen Seite)
getattr(p, 'y')
# Ergebnis: 4
getattr(p, 'z', 0)
# Ergebnis: 0
Wird kein Standard-Wert angegeben und das Attribut existiert nicht, so wird ein
AttributeError ausgelöst.
globals()
Die Funktion globals() liefert als Ergebnis ein dict mit den Namen und den Werten aller
zum Zeitpunkt des Aufrufs existierenden globalen, das heißt programmweit sichtbaren
Variablen.
Beispiel:
globals()
# Ergebnis:
# {'__doc__': None, '__spec__': None, '__name__': '__main__',
# '__package__': None, # '__loader__': <class '_frozen_importlib.BuiltinImporter
˓→'>,
hasattr()
Die Funktion hasattr(objekt, attributname) gibt als Ergebnis den Wahrheitswert True zu-
rück, falls für das angegebene Objekt ein Attribut mit dem angegebenen Namen existiert,
andernfalls False.
Beispiel:
# Beispiel-Klasse:
class Point():
x = 5
y = 4
# Punkt-Objekt erzeugen:
p = Point()
hasattr(p, 'x')
# Ergebnis: True
hasattr(p, 'y')
# Ergebnis: True
155
(Fortsetzung der vorherigen Seite)
getattr(p, 'z')
# Ergebnis: False
Mittels der Funktion hasattr() kann somit geprüft werden, ob die Funktion getattr()
beim Aufruf einen AttributeError auslösen wird oder nicht.
hash()
Die Funktion hash(unveraenderliches-objekt) liefert zu beliebigen nicht veränderlichen
Python-Objekten (beispielsweise Zeichenketten oder Tupeln) einen eindeutigen Integer-
Wert als Ergebnis zurück; dieser ist nicht abhängig von der aktuellen Python-Sitzung.
Identische Objekte werden durch die hash()-Funktion also auf identische ganzzahlige
Werte abgebildet.
Beispiel:
hash("Hallo Welt!")
# Ergebnis: -2446188496090613429
hash( (1, 3, 5, 7, 9) )
# Ergebnis: -4331119994873071480
Die Umkehrung ist leider nicht zwingend eindeutig: Zu einem Hash-Wert können unter-
schiedliche Objekte gehören.
help()
Die Funktion help(objekt) blendet im Interpreter eine Hilfe-Seite zum angegebenen Objekt
ein, sofern eine Dokumentation zum angegebenen Objekt vorhanden ist.
Beispiel:
hex()
Die Funktion hex(int-wert) gibt eine Zeichenkette mit der Hexadezimal-Darstellung einer
Integer-Zahl als Ergebnis zurück. Eine solche Zeichenkette wird mit 0x eingeleitet, gefolgt
von der eigentlichen Binärzahl.
Beispiel:
156
hex(42)
# Ergebnis: '0x2a'
id()
Die Funktion id(objekt) liefert für beliebige Python-Objekte, abhängig von der aktu-
ellen Python-Sitzung, einen eindeutigen Integer-Wert als Ergebnis zurück; dieser Wert
entspricht der Adresse, an der das Objekt im Speicher abgelegt ist.
Beispiel:
id("Hallo Welt!")
# Ergebnis: 139882484400688
Mittels der Funktion id() können somit zwei Objekte auf Gleichheit getestet werden.
input()
Die Funktion input() dient zum Einlesen einer vom Benutzer eingegebenen Zeichenkette.
Beim Aufruf kann dabei optional ein String angegeben werden, der dem Benutzer vor dem
Eingabe-Prompt angezeigt wird:
Soll eine Zahl eingelesen werden, so muss die Benutzerantwort mittels int() bzw. float()
explizit von einem String in eine solche umgewandelt werden.
int()
Die Funktion int() gibt, sofern möglich, die zur angegebenen Zeichenkette oder
Gleitkomma-Zahl passende Integer-Zahl als Ergebnis zurück; wird eine float-Zahl als
Argument übergeben, so werden mögliche Nachkommastellen schlichtweg ignoriert, bei-
spielsweise ergibt int(3.7) den Wert 3.
Beispiel:
int('5')
# Ergebnis: 5
int(3.14)
# Ergebnis: 3
157
isinstance()
Die Funktion isinstance(objekt, klassen-name) gibt als Ergebnis den Wahrheitswert True
zurück, wenn das angegebene Objekt eine Instanz der als zweites Argument angegebe-
nen Klasse (oder einer Subklasse ) ist; ist dies nicht der Fall, wird False als Ergebnis
zurückgegeben.
Gibt man als zweites Argument eine Liste mit Klassennamen an, so wird geprüft, ob das
angegebene Objekt eine Instanz einer der in der Liste angegebenen Klassen ist:
Beispiel:
issubclass()
Die Funktion issubclass(cls1, cls2) gibt als Ergebnis den Wahrheitswert True zurück,
wenn die als erstes Argument angegebene Klasse eine Subklasse der als zweites Argument
angegebenen Klasse ist; ist dies nicht der Fall, wird False als Ergebnis zurückgegeben.
Beispiel:
isinstance(str, object)
# Ergebnis: True
iter()
Die Funktion iter(sequenz) erstellt eine neue Instanz eines Iterator-Objekts aus einer
listen-artigen Sequenz (genauer: einem Objekt mit einer __iter__()-Methode). Dieser
Iterator kann beispielsweise verwendet werden, um eine for-Schleife über die in der Se-
quenz vorkommenden Elemente zu konstruieren:
Beispiel:
# Iterator generieren:
iterator = iter( ['Hallo', 'Welt'] )
# Ergebnis:
# Hallo
# Welt
158
Die einzelnen Elemente eines Iterator-Objekts können auch schrittweise mittels
iteratorname.__next__() aufgerufen werden; ist man am Ende der Sequenz angekom-
StopIteration-Error ausgelöst.
men, so wird ein
Eine zweite Verwendungsmöglichkeit der iter()-Funktion besteht darin, als erstes Ob-
jekt einen Funktions- oder Methodennamen und als zweites Argument eine Integer-Zahl
als „Grenzwert“ anzugeben. Wird ein solcher „aufrufbarer“ Iterator mit iteratorname.
__next__() aufgerufen, so wird die angegebene Funktion so lange aufgerufen, bis diese
einen Rückgabewert liefert, der mit dem angegebenen Grenzwert identisch ist. Wird der
Grenzwert nicht erreicht, so kann der Iterator beliebig oft aufgerufen werden.
Beispiel:
import random
# Zufallszahlen ausgeben:
iterator.__next__()
# Ergebnis: 0.17789467192460118
iterator.__next__()
# Ergebnis: 0.7501975823469289
len()
Die Funktion len() gibt die Länge einer Liste oder Zeichenkette als int-Wert an. Bei
einer Liste wird die Anzahl an Elementen gezählt, bei einer Zeichenkette die einzelnen
Textzeichen, aus denen die Zeichenkette besteht.
Beispiel:
len('Hallo Welt!')
# Ergebnis: 11
len( str(1000) )
# Ergebnis: 4
len( [1,2,3,4,5] )
# Ergebnis: 5
list()
Die Funktion list() erzeugt eine neue Instanz eines list -Objekts, also eine (veränderliche)
Liste. Formal ist l = list() somit identisch mit l = [ ].
159
Wird beim Aufruf von list() eine Sequenz angegeben, so wird die Liste mit den in der
Sequenz vorkommenden Einträgen gefüllt.
Beispiel:
l2
# Ergebnis: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
locals()
Die Funktion locals() liefert als Ergebnis ein dict mit den Namen und den Werten al-
ler zum Zeitpunkt des Aufrufs existierenden lokalen, das heißt im aktuellen Codeblock
sichtbaren Variablen.
map()
Die Funktion map(function, object) wendet eine Funktion auf alle Elemente eines ite-
rierbaren Objekts (beispielsweise einer Liste) an. Als Ergebnis liefert map() ein neues
iterierbares Objekt, dessen Elemente den einzelnen Ergebniswerten entsprechen.
Beispiel:
Oftmals wird anstelle der map()-Funktion eine (meist besser lesbare) List-Comprehension
genutzt. Im obigen Beispiel könnte auch [abs(x) for x in my_list] geschrieben wer-
den.
max()
Die Funktion max() gibt das größte Element einer Liste als Ergebnis zurück.
Beispiel:
max( [5,1,3,9,7] )
# Ergebnis: 9
160
min()
Die Funktion min() gibt das kleinste Element einer Liste als Ergebnis zurück.
Beispiel:
min( [5,1,3,9,7] )
# Ergebnis: 1
next()
Die Funktion next(iterator) bewirkt einen Aufruf von iterator.__next__(), gibt
also das nächste Element der Iterator-Sequenz aus. Ist der Iterator am Ende der Sequenz
angelangt, so wird von next(iterator) ein StopIteration-Error ausgegeben.
Beispiel:
# Iterator generieren:
iterator = iter( ['Hallo', 'Welt'] )
next(iterator)
# Ergebnis: 'Hallo'
next(iterator)
# Ergebnis: 'Welt'
next(iterator)
# Ergebnis:
# --> 1 next(iterator)
# StopIteration
object()
Die Funktion object() erzeugt eine Instanz eines neuen object-Objekts. Ein objekt ist
die Basisklasse aller Objekte, hat allerdings keine besonderen Attribute oder Methoden.
Beim Aufruf von object() dürfen keine weiteren Argumente angegeben werden; zudem
verfügt ein object-Objekt über kein __dict__, so dass der Instanz keine weiteren Attri-
bute oder Methoden hinzugefügt werden können.
oct()
Die Funktion oct(int-wert) gibt eine Zeichenkette mit der Oktaldarstellung einer int-
Zahl als Ergebnis zurück. Eine solche Zeichenkette wird mit 0o eingeleitet, gefolgt von
der eigentlichen Oktalzahl.
Beispiel:
161
oct(42)
# Ergebnis: '0o52'
open()
Die Funktion open(dateiname) gibt ein zum angegebenen Pfad passendes Datei-Objekt
als Ergebnis zurück, das zum Lesen oder Schreiben von Dateien verwendet wird.
ord()
Die Funktion ord(zeichen) gibt die Unicode-Zahl (ein int-Wert) eines angegebenen Zei-
chens (Buchstabe, Zahl, oder Sonderzeichen) aus.
Beispiel:
ord('A')
# Ergebnis: 65
ord('a')
# Ergebnis: 97
Für viele Programme reichen die ASCII-Codes als Teilmenge des Unicode-Zeichensatzes
bereits aus.
pow()
Die Funktion pow(zahl1, zahl2) gibt beim Aufruf von pow(x,y) den Wert von x ** y,
also x hoch y aus (Potenz).
Beispiel:
pow(10, 3)
# Ergebnis: 1000
pow(10, -3)
# Ergebnis: 0.001
print()
Die Funktion print(zeichenkette) gibt die angegebene Zeichenkette auf dem Bildschirm
aus; dabei können unter anderem mittels einer geeigneten Formatierung auch Werte von
Variablen ausgegeben werden.
Beispiel:
162
print("Die Antwort lautet %d .", % 42)
# Ergebnis: Die Antwort lautet 42.
property()
Die Funktion property() wird verwendet, um auf ein Attribut einer Klasse nicht
direkt, sondern mittels einer Methode zuzugreifen. Hierzu wird in der Klasse des
Objekts je eine Setter- und Getter -Methode definiert, die zum Zuweisen und Ab-
rufen des Attributs verwendet werden. Anschließend kann mittels my_attribute =
property(fget=getterfunction, fset=setterfunction) ein Property-Attribut er-
zeugt werden.
# Testklasse definieren:
class C():
# Testklasse definieren:
class C():
163
Erzeugt man mittels c = C() ein neues Objekt der obigen Beispielklasse, so kann auch
mittels c.bar auf das Attribut c.foo zugegriffen werden:
c.bar
# Ergebnis: 1
c.foo
# Ergebnis: 2
Üblicherweise erhält die Zielvariable, die von der Property verändert wird, den gleichen
Namen wie die Property selbst, jedoch mit einem _ zu Beginn des Variablennamens.
Hierdurch wird ausgedrückt, dass die Variable nicht direkt verändert werden sollte (ob-
gleich dies möglich wäre). In der Setter-Funktion kann dann beispielsweise explizit geprüft
werden, ob eine vorgenommene Wertzuweisung überhaupt zulässig ist.
range()
Die Funktion range() erzeugt eine Sequenz ganzzahliger Werte. Sie kann wahlweise in
folgenden Formen benutzt werden:
range(stop)
range(start, stop)
range(start, stop, step)
Wird der range()-Funktion nur ein einziger Wert 𝑛 als Argument übergeben, so wird
eine Zahlensequenz von 0 bis 𝑛 − 1 generiert; Werden zwei Werte 𝑚 und 𝑛 übergeben,
so wird eine Zahlensequenz von 𝑚 bis 𝑛 − 1 erzeugt. Allgemein ist bei Verwendung von
range() die untere Schranke im Zahlenbereich enthalten, die obere hingegen nicht.
Wird eine dritte Zahl 𝑖 ̸= 0 als Argument angegeben, so wird nur jede 𝑖-te Zahl im ange-
gebenen Zahlenbereich in die Sequenz aufgenommen. Ist der Startwert des Zahlenbereichs
größer als der Stopwert und 𝑖 negativ, so wird eine absteigende Zahlensequenz generiert.
Beispiel:
range(10)
# Ergebnis: range(0,10)
164
(Fortsetzung der vorherigen Seite)
repr()
Die Funktion repr(objekt) gibt als Ergebnis eine Zeichenkette zurück, die eine kurze cha-
rakteristische Beschreibung des Objekts beinhaltet; häufig entspricht dies einer Angabe
der Objekt-Klasse, des Objekt-Namens und der Speicheradresse.
Beispiel:
repr(print)
# Ergebnis: '<built-in function print>'
Ist in der Klasse des angegebenen Objekts eine __repr__()-Methode definiert, so ist
repr(objekt) identisch mit objekt.__repr__().
Als Zeichensatz wird für die Ausgabe des Strings Unicode verwendet, so dass beispielsweise
auch Umlaute im Ausgabe-String enthalten sein können.
reversed()
Die Funktion reversed(sequenz) kann auf eine iterierbares Objekt (beispielsweise ein Tupel
oder eine Liste) angewendet werden; sie gibt einen Iterator mit den gleichen Elementen,
aber in der umgekehrten Reihenfolge zurück.
Beispiel
liste = [1,5,2,3]
liste_rev = reversed(liste)
liste_rev
# Ergebnis: <builtins.list_reverseiterator at 0x7f38edce2278>
for i in liste_rev:
print(i)
# Ergebnis:
# 3
# 2
# 5
# 1
165
round()
Die Funktion round() rundet eine float-Zahl auf die nächste int-Zahl auf beziehungswei-
se ab und gibt diese als Ergebnis zurück. Wird zusätzlich zur Zahl eine zweite Integer-Zahl
als Argument angegeben, also round(a, n), so wird die Zahl a auf n Stellen gerundet als
Ergebnis zurück gegeben.
round(15.37)
#Ergebnis: 15
round(15.37, 1)
#Ergebnis: 15.4
set()
Die Funktion set() erzeugt ein neues set -Objekt, also eine Menge.
Wird optional beim Aufruf von set() eine Sequenz als Argument angegeben, so wird
das Mengen-Objekt mit den Einträgen dieser Menge gefüllt (doppelte Einträge bleiben
ausgeschlossen).
Beispiel:
s2
# Ergebnis: set({1, 3, 5, 7, 9})
s3
# Ergebnis: set({' ', '!', 'H', 'W', 'a', 'e', 'l', 'o', 't'})
setattr()
Die Funktion setattr(objekt, attributname, wert) weist dem angegebenen Attribut des
als erstes Argument angegebenen Objekts den als drittes Argument angegebenen Wert
setattr(objekt, attributname, wert)
zu (sofern dies möglich ist); formal ist somit
identisch mit objekt.attributname = wert.
Beispiel:
166
# Beispiel-Klasse:
class Point():
x = 5
y = 4
# Punkt-Objekt erzeugen:
p = Point()
# Attribut ändern:
setattr(p, 'x', 3)
# Attribut abrufen:
getattr(p, 'x')
# Ergebnis: 3
# Attribut abrufen:
getattr(p, 'z')
# Ergebnis: 2
slice()
Die Funktion slice(startwert, stopwert, stepwert) erstellt eine neue Instanz eines Slice-
Objekts. Dieses Objekt repräsentiert einen Satz an Indizes, der durch die angegebenen
Werte unveränderbar festgelegt ist.
Beispiel
s = slice(0,10,2)
s.start
# Ergebnis:0
s.stop
# Ergebnis:10
s.step
# Ergebnis:2
Beim Aufruf von slice() kann als Wert für die Argumente start und stop auch None
angegeben werden. Das Slice-Objekt enthält dann nur step als unveränderlichen Wert.
Wird das Slice-Objekt mit s bezeichnet, so kann in diesem Fall beispielsweise mittels s.
indices(100) ein neues Slice-Objekt als Ergebnis geliefert werden, das den angegebenen
Wert als stop-Wert hat.
Slice-Objekte werden selten direkt verwendet. Allerdings werden bei Datentypen wie Zei-
chenketten oder Listen Slicings gerne zur Auswahl von Elementen genutzt; ebenso kön-
167
nen bei Verwendung von Modulen wie numpy oder pandas Slicings eingesetzt werden, um
mittels den dabei resultierenden Indizes Teilbereiche aus Zahlenlisten zu selektieren. Die
Syntax lautet dabei etwa:
a = numpy.arange(10)
a[3:8]
# Ergebnis: array([3, 4, 5, 6, 7])
a[3:8:2]
# Ergebnis: array([3, 5, 7])
Verwendet man die gleichnamige Funktion slice() aus dem itertools-Modul, so wird
als Ergebnis statt einem Slice ein entsprechendes Iterator-Objekt zurückgegeben.
sorted()
Die Funktion sorted(sequenz) kann auf eine iterierbares Objekt (beispielsweise ein Tupel
oder eine Liste) angewendet werden; sie gibt eine Liste mit den entsprechenden Elementen
in sortierter Reihenfolge zurück.
Beispiel
sorted([1,5,2,3])
# Ergebnis: [1, 2, 3, 5]
staticmethod()
Die Funktion staticmethod(methode) macht die angegebene Methode zu einer so genann-
ten statischen Methode. Üblicherweise wird die staticmethod()-Funktion als Funktions-
dekorator verwendet:
class C():
@staticmethod
def my_static_method(arguments):
pass
Bei einer so definierten Methode wird weder der Name der Klasse noch der Name der
Instanz angegeben, von der aus die Methode aufgerufen wird.
Die statische Methode des obigen Beispiels kann wahlweise mittels C.my_class_method()
oder ausgehend von einer Instanz der Klasse, also mittels C().my_class_method() auf-
gerufen werden.
168
str()
Die Funktion str(objekt) gibt eine String-Version des als Argument angegebenen Objekts
aus. Hierbei wird die Methode objekt.__str__() der jeweiligen Klasse aufgerufen.
Beispiel:
str( [1,2,3,4,5] )
# Ergebnis: '[1, 2, 3, 4, 5]'
sum()
Die Funktion sum(sequenz) gibt die Summe eines iterierbaren Objekts (beispielsweise
einer Liste) als Ergebnis zurück.
Beispiel:
sum( [1,2,3,4,5] )
# Ergebnis: 15
sum( range(100) )
# Ergebnis: 4950
super()
Die Funktion super() gibt, ausgehend von der Klasse des aufrufenden Objekts, die in
der Objekt-Hierarchie nächst höher liegende Klasse an; dies wird insbesondere bei der
Vererbung von Methoden genutzt.
Die Objekt-Hierarchie gibt eine Art Stammbaum für die Klasse an. Über das Attribut
__mro__ einer Klasse („Method Resolution Order“) kann abgefragt werden, in welcher Rei-
henfolge Klassen bei einem Methodenaufruf nach einer entsprechend benannten Methode
durchsucht werden.
Beispiel:
import enum
enum.OrderedDict.__mro__
# Ergebnis: (collections.OrderedDict, builtins.dict, builtins.object)
Wird beispielsweise beim Aufruf von obj.eine_methode() die Methode nicht im Na-
mensraum des Objekts gefunden, so wird entlang der Method Resolution-Order geprüft,
ob eine gleichnamige Methode in einer übergeordneten Klasse definiert ist. Ist dies der
Fall, so wird die Methode dieser Klasse aufgerufen, da die konkrete Klasse des Objekts
die Methoden „geerbt“ und nicht überschrieben hat. Den Zugriff auf die jeweils nächste
Klasse der Method Resolution Order bietet gerade die Funktion super().
169
Beim Programmieren kann die Funktion super(), die in Python3 fast immer ohne Ar-
gumente aufgerufen wird, genutzt werden, um eine Methode der übergeordneten Klasse
aufzugreifen und gleichzeitig zu modifizieren.
tuple()
Die Funktion tuple(sequenz) erzeugt aus der angegebenen Sequenz (beispielsweise einer
Liste oder einer Zeichenkette) eine neue Instanz eines tuple -Objekts, also eine unverän-
derliche Liste.
Beispiel:
tuple('Hallo Welt!')
# Ergebnis: ('H', 'a', 'l', 'l', 'o', ' ', 'W', 'e', 'l', 't')
tuple( range(10) )
# Ergebnis: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
type()
Die Funktion type(objekt) gibt als Ergebnis den Namen der Klasse des angegebenen
Objekts zurück; dies ist identisch mit einem Aufruf von objekt.__class__.
Beispiel:
type("Hallo Welt!")
# Ergebnis: builtins.str
Die folgenden beiden Code-Varianten erzeugen jeweils ein Objekt mit gleichen Eigenschaf-
ten:
# Beispielklasse definieren:
class C(object):
x = 1
# Beispiel-Objekt generieren:
c1 = C()
170
vars()
Die Funktion vars() gibt, sofern sie ohne Argument aufgerufen wird, als Ergebnis ein dict
mit den Namen und den Werten aller zum Zeitpunkt des Aufrufs existierenden lokalen,
das heißt im aktuellen Codeblock sichtbaren Variablen zurück (ebenso wie locals() ).
Wird beim Aufruf von vars() als Argument ein beliebiges Objekt angegeben, so wird der
Inhalt von objekt.__dict__ als Ergebnis zurückgegeben.
zip()
Die Funktion zip() verbindet – ähnlich wie ein Reißverschluss – Elemente aus verschiede-
nen iterierbaren Objekten (beispielsweise Listen) zu einem neuen Iterator-Objekt, dessen
Elemente Zusammensetzungen der ursprünglichen Elemente sind.
Beispiel:
Wichtige Standard-Module
Das cmath-Modul umfasst viele Funktionen des math-Moduls, die allerdings komplexe
Zahlen als Argumente zulassen.
Das copy-Modul stellt insbesondere die Funktion deepcopy() bereit, mit der 1 : 1-Kopien
von existierenden Objekten gemacht werden können.
Erstellt man eine Kopie eines Objekts mittels objekt2 = objekt1.copy(), so wird genau
genommen nur eine neue Referenz auf das bestehende Objekt angelegt. Hat objekt1
beispielsweise ein Attribut x mit dem Wert 5, so würde durch eine Eingabe von objekt2.x
= 7 auch der Attribut-Wert von objekt1 geändert. Ein solches Verhalten ist beispielsweise
bei der Übergabe von Objekten an Funktionen erwünscht, entspricht allerdings nicht der
klassischen Vorstellung einer Kopie. Eine solche kann folgendermaßen erstellt werden:
171
import copy
Werden nun die Attribut-Werte von objekt2 geändert, so bleiben die Werte des Original-
Objekts unverändert.
cProfile – Profiler
Mittels des Pakets cProfile und der darin definierten Funktion run() kann ermittelt wer-
den, wie viel Zeit für einen Aufruf einer Funktion benötigt wird. Bei einer Funktion, die
weitere Unterfunktionen aufruft, wird zudem angezeigt, wie viel Zeit auf die einzelnen
Schritte entfällt:
import cProfile
cProfile.run('sum( range(10000000) )')
# Ergebnis:
# 4 function calls in 0.321 seconds
Das functools-Modul stellt einige Funktionen bereit, mit denen sich beispielsweise mathe-
matische Funktion oder Lambda-Ausdrücke auf mehrere Elemente einer Liste anwenden
lassen
Die Funktion functools.reduce() führt die durch das erste Argument angegebene
Funktion schrittweise von links nach rechts auf alle Elemente einer als zweites Ar-
gument übergebenen Sequenz aus; ein Aufruf von ft.reduce(lambda x,y: x*y,
[1,2,3,4,5]). würde beispielsweise ((((1*2)*3)*4)*5) berechnen.
172
logging – Logger-Modul
Das logging-Modul stellt einfache Funktionen bereit, mit denen ein einfaches Aufzeichnen
verschiedener Informationen im Verlauf eines Programms ermöglicht wird.
Mit math.pow(zahl, n) wird die n-te Potenz der angegebenen Zahl ausgegeben.
Für 𝑛 kann auch eine float-Zahl kleiner als 1 angegeben werden; beispielsweise
wird durch math.pow(8, 1/3) die dritte Wurzel von 8 berechnet.
Das math-Modul ist für die Berechnung einzelner Werte vorgesehen. Für die Berechnung
von Zahlenreihen stellt das Zusatz-Modul numpy gleichnamige Funktionen bereit. Die-
se können jeweils nicht nur einen einzelnen Wert, sondern jeweils auch eine Liste von
entsprechenden Zahlenwerten als Argument effizient auswerten.
173
os – Interaktion mit dem Betriebsystem
Das os-Modul stellt einige nützliche Funktionen und Konstanten bereit, um gewöhnliche
Aufgaben auf der Ebene des Betriebsystems durchführen zu können.
Mit os.chdir(pfad) wird das als Argument angegebene Verzeichnis zum aktuellen
Arbeitsverzeichnis.
Mit os.listdir(pfad) wird eine Liste aller Dateinamen des als Argument angege-
benen Verzeichnisses ausgegeben.
Mit os.rename(alt, neu) wird einer Datei oder einem Verzeichnis ein neuer Name
zugewiesen.
Mit der Funktion os.popen() ist es zudem möglich, ein Programm in einer gewöhnlichen
Shell aufzurufen. Hierzu wird der Funktion os.popen() als Argument eine Zeichenkette
angegeben, deren Inhalt an den Shell-Interpreter weitergereicht wird. Die Ausgabe des
Programms wird in eine Pipe geschrieben, die wie ein Datei -Objekt wahlweise zeilenweise
mittels readline() oder als Ganzes mittels read() ausgelesen werden kann:
import os
# Shell-Anweisung festlegen:
command = 'ls -l'
# Shell-Anweisung ausführen:
# (Der Rückgabewert ist ein Filepointer auf die Pipe)
fp = os.popen(command)
# Pipe schließen:
# (Status == None bedeutet fehlerfreies Schließen)
status = fp.close()
os.path – Pfadfunktionen
Das os.path-Modul stellt einige nützliche Funktionen bereit, die bei der Arbeit mit Datei-
und Verzeichnisnamen hilfreich sind:
174
Mit os.path.exists(pfad) kann geprüft werden, ob der als Argument angegebene
Dateiname als Pfad im Dateisystem existiert; als Ergebnis gibt die Funktion True
oder False zurück.
Mit os.path.getsize(pfad) kann der vom als Argument angegebenen Pfad belegte
Speicherplatz ausgegeben werden.
Um nicht nur relative, sondern auch absolute Pfadangaben nutzen zu können, kann die
Funktion os.path.abspath(pfad) genutzt werden; diese gibt zu einem angegebenen (re-
lativen) Dateinamen den zugehörigen absoluten Pfad an.
Um ein beliebiges Python-Objekt mittels pickle als Zeichenkette zu codieren, gibt man
folgendes ein:
import pickle
liste_original = [1,2,3,4,5]
Hierbei steht dumps für „dump string“. Der erzeugte Byte-String ist zwar für Menschen
nicht unmittelbar lesbar, kann aber vom Computer effizient geschrieben und auch mittels
pickle.loads() („load string“) wieder ausgelesen werden:
# Byte-String zurückübersetzen:
liste_neu = pickle.loads(storage)
liste_neu
# Ergebnis: [1,2,3,4,5]
Das wieder geladene Objekt ist inhaltlich mit dem Original identisch, wird vom Interpreter
jedoch als neues Objekt gehandhabt.
Soll das Ablegen eines Objekts unmittelbar in eine Datei erfolgen, so kann anstelle von
pickle.dumps() die Funktion pickle.dump() verwendet und dabei als Argument ein
existierender File-Pointer angegeben werden. Umgekehrt kann mittels pickle.load()
wieder unmittelbar aus dem als Argument angegebenen Datei-Objekt gelesen werden.
175
random – Zufallsgenerator
Das random-Modul stellt Funktion zum Erzeugen von Zufallszahlen, für das Auswählen
eines zufälligen Elements aus einer Liste sowie für das Umsortieren von Listen bereit.
Zu Beginn sollte zunächst stets eine neue Basis für die Erzeugung von Zufallszahlen in
der aktuellen Python-Sitzung erstellt werden:
import random
# Zufallszahlen initiieren:
random.seed()
Die Funktion random.random() liefert als Ergebnis eine Zufallszahl zwischen 0.0
und 1.0 (einschließlich dieser beiden Werte).
Die Funktion random.choice(sequenz) wählt ein zufälliges Element aus einer Se-
quenz (beispielsweise einer Liste oder einem Tupel) aus.
Die Funktion random.shuffle(liste) ordnet die Elemente einer Liste auf zufällige
Weise neu an; dabei wird das Original verändert.
sys – Systemzugriff
Das sys-Modul stellt Variablen und Funktion bereit, die in unmittelbarem Zusammenhang
mit dem Python-Interpreter selbst stehen. Hilfreich sind unter anderem:
Mit sys.path erhält man eine Liste mit Pfadnamen, in denen beim Aufruf von
import nach Modulen gesucht wird.
Mit sys.stdin, sys.stdout und sys.stderr hat man Zugriff zu den drei gewöhn-
lichen Shell-Kanälen (Eingabe, Ausgabe, Fehler). In Python werden diese wie ge-
wöhnliche Datei -Objekte behandelt.
176
timeit – Laufzeitanalyse
Mittels des Moduls timeit und der gleichnamigen Funktion aus diesem Paket kann einfach
ermittelt werden, wieviel Zeit eine Funktion für einen Aufruf benötigt:
import timeit
timeit.timeit("x = 2 ** 2")
# Ergebnis: 0.02761734207160771
ASCII-Codes
Dez AS- Dez AS- Dez AS- Dez AS- Dez AS- Dez AS- Dez AS- Dez AS-
CII CII CII CII CII CII CII CII
0 NUL 16 DLE 32 SP 48 0 64 @ 80 P 96 ‘ 112 p
1 SOH 17 DC1 33 ! 49 1 65 A 81 Q 97 a 113 q
2 STX 18 DC2 34 " 50 2 66 B 82 R 98 b 114 r
3 ETX 19 DC3 35 # 51 3 67 C 83 S 99 c 115 s
4 EOT 20 DC4 36 $ 52 4 68 D 84 T 100 d 116 t
5 ENQ 21 NAK 37 % 53 5 69 E 85 U 101 e 117 u
6 ACK 22 SYN 38 & 54 6 70 F 86 V 102 f 118 v
7 BEL 23 ETB 39 ' 55 7 71 G 87 W 103 g 119 w
8 BS 24 CAN 40 ( 56 8 72 H 88 X 104 h 120 x
9 HT 25 EM 41 ) 57 9 73 I 89 Y 105 i 121 y
10 LF 26 SUB 42 * 58 : 74 J 90 Z 106 j 122 z
11 VT 27 ESC 43 + 59 ; 75 K 91 [ 107 k 123 {
12 FF 28 FS 44 , 60 < 76 L 92 \ 108 l 124 |
13 CR 29 GS 45 - 61 = 77 M 93 ] 109 m 125 }
14 SO 30 RS 46 . 62 > 78 N 94 ^ 110 n 126 ~
15 SI 31 US 47 / 63 ? 79 O 95 _ 111 o 127 DEL
177
Links
Offizielle Seiten
Python Vortrags-Folien
Code-Suche
Private Python-Seiten
178
Tips und Tricks
Python Code-Beispiel-Suchmaschine
179
Stichwortverzeichnis
Symbols class, 43
__dict__, 48
__eq__(), 48
D
__ge__(), 49 Dataframe(), 110
48 def(), 35
__hash__(), 49 dict, 27
__main__, 55 Docstring, 14
__name__, 55 Doctest, 67
__ne__(), 48
__repr__(), 47
E
elif, 31
__setattr__(), 48
else, 31
__slots__, 48
enumerate(), 151
__str__(), 47
Euklid-Algorithmus, 80
__type__(), 44
eval(), 151
A except, 61
exec(), 152
abs(), 145
extend(), 22
all(), 145
any(), 146
append(), 22
F
False, 11
ascii(), 146
file, 29
ASCII-Codes, 177
filter(), 152
Attribut, 42
float, 12
Ausnahme, 61
float(), 153
Auswertungsreihenfolge, 7
for, 33
B format(), 153
180
getattr(), 154 min(), 12, 160
globals(), 155 Modul, 53
H N
hasattr(), 155 next(), 161
hash(), 156 None, 10
help(), 4, 156 numpy, 101
hex(), 156
O
I object(), 161
import(), 54 Operator, 7
in, 20 Operator-Überladung, 47
int(), 157
Ipython (IDE), 81
P
isinstance(), 157 Paket, 56
Komplexe Zahlen, 12
Kontrollstruktur, 30
R
L
raise, 62
random (Modul), 175
lambda, 40 range(), 164
len(), 159 read(), 29
Liniendiagramme, 89 readline(), 29
list(), 19, 159 readlines(), 29, 30
Liste, 19 repr(), 165
locals(), 160 reversed(), 165
Logdatei, 66 round(), 165
S
logging (Modul), 172
M Schleife, 32
Magic Member, 47 for, 33
map(), 160 while, 32
math (Modul), 173 Series(), 108
Matplotlib, 88 set, 26
max(), 12, 160 set(), 166
Member, 45 setattr(), 166
Menge, 26 slice(), 167
Methode, 42 sorted(), 168
181
staticmethod(), 47, 168
Statische Methode, 46, 47
Statisches Attribut, 46
str(), 13, 168
String, 13
sum(), 169
super(), 169
sympy, 117
T
Ternärer Operator, 8
True, 11
try, 61
Tupel, 19
tuple(), 19, 170
type(), 170
U
Unittest, 68
V
values() (dict-Methode), 28
Variable, 6
vars(), 170
Vererbung, 51
View, 28
virtualenv, 1
W
while, 32
write(), 30
Z
Zeichenkette, 13
count(), 16
endswith(), 16
find(), 16
join(), 18
replace(), 17
rfind(), 16
split(), 18
startswith(), 16
Zeitreihe, 109
zip(), 171
Zufallszahlen, 175
Zuweisungsoperator, 7
182