Python ist eine freie, offene, plattformunabhängige, üblicherweise interpretierte, höhere Programmiersprache. Python Code ist gut lesbar und einfach zu lernen. Es gibt sehr viele Pakete und Einsatzgebiete für Python, siehe PyPI - the Python Package Index. Für den Bereich des wissenschaftlichen Rechnens sind insbesondere die SciPy-Pakete nützlich. Python erfreut sich einer großen und wachsenden Beliebtheit und besitzt daher eine umfangreiche und breitgefächert Community. So ziemlich jedes Problem mit Lösung/en findet man z. B. unter stackoverflow. Der Name bezieht sich übrigens auf die englische Komikergruppe Monty Python.
Installation: Python und Python Pakete können auf sehr unterschiedliche Art und Weise installiert werden. Wir verwenden die von vielen empfohlene Variante der Python Distribution Anaconda. Um die Anaconda Individual Edition zu installieren, folgen Sie den Hinweisen entsprechend Ihrem Betriebssystem.
Zu den Alternativen im Bereich wissenschaftliches Rechnen zählen
Es gibt, grob gesagt, zwei Typen von Entwicklungsumgebungen:
Ein Text-Editor kombiniert mit der Kommandozeile (englisch: command prompt, console, terminal). Entwicklungsumgebungen wie Spyder, Visual Studio Code oder PyCharm kombinieren beides und mehr in einer Applikation.
Wir verwenden die web-basierte, interaktive, literate programming Entwicklungsumgebung JupyterLab, die neben Python noch viele andere Programmiersprachen mittels Jupyter-Notebooks untersützt. Im Wikipedia-Eintrag zum Projekt Jupyter steht (Stand 2020-06-18) unter anderem: “Das Jupyter Notebook hat sich als Benutzeroberfläche für Cloud Computing verbreitet. Große Cloud-Anbieter haben angepasste Tools für Cloud-Anwender entwickelt. Beispiele dafür sind Amazon SageMaker, Googles Colaboratory und Microsofts Azure Notebook.”
JupyterLab
Starten Sie anschließend JupyterLab via dem Anaconda Navigator oder einfacher über eine Kommandozeile mit dem Befehl jupyter lab. Das meiste der browserbasierten Oberfläche ist selbsterklärend. Wenn Sie ein (neues) Jupyter Notebook (Dateiendung .ipynb) starten, wird ein Kernel gestartet. Der Kernel führt Ihre Python Befehle aus und beeinhaltet alle verwendeten Objekte (Variablen, Funktionen, Pakete etc.).
Achtung: Verwenden Sie generell für Ordner- und und Dateinamen keine Umlaute, keine Sonderzeichen und keine Leerzeichen!
Ein Jupyter-Notebook besteht aus einer Liste von Zellen (engl. cells). Zellen können im Command Mode oder im Edit Mode bearbeitet werden. Die wichtigsten zwei Zelltypen sind Code und Markdown.
Code Zellen:
Wir schreiben unseren Python Code in die Code-Zellen eines Jupyter-Notebooks. Zum Ausführen des Codes einer Code-Zelle drücken Sie Strg+Return oder Shift+Return. Bei der ersten Variante bleibt der Fokus auf der Code-Zelle, bei der zweiten springt man in die nächste Zelle.
Der Rückgabewert des letzten Befehls einer Code Input-Zelle wird in einer folgenden Code Output-Zelle ausgegeben. Sie können die Ausgabe mit einem Strichpunkt am Ende des letzten Befehls unterdrücken.
Funktionen haben runde Klammern. Hilfe z. B. zur Funktion print erhalten Sie durch help(print) oder print? oder SHIFT-TAB drücken, wenn der Cursor nach der ersten runden Klammer von print() steht.
Eine Liste der von Ihnen definierten Variablen erhalten Sie mit dem magic command %whos. Löschen einzelner Variablen, hier z. B. der Variable x, erfolgt mit dem Befehl del(x). Löschen aller selber definierten Variablen erfolgt mit dem Befehl %reset -s.
Tipp: Verwenden Sie die Tabulator-Vervollständigung beim Coden!
Tipp: Mit der Tastenkombination Strg+I öffnet sich der sehr hilfreiche Contextual Help Tab.
Tipp: Öffnen Sie eine Console für Ihr Notebook, um außerhalb des Notebooks interaktiv Befehle im Namespace des Notebook-Kernels auszuführen.
Markdown Zellen:Markdown ist eine vereinfachte Auszeichnungssprache, die bereits in der Ausgangsform ohne weitere Konvertierung leicht lesbar ist. Sie können in Markdown sehr leicht folgenden strukturierten Text erstellen:
Überschirften: Rautesymbol(e) vor der Überschrift
Listen: mit Minus-, Plus- oder Sternzeichen
Links: mit Syntax [Name](URL)
Bilder: mit Syntax ![Name](Pfad-zu-Bilddatei)
Mathematische Formeln wie z. B. \(K = \frac{mv^2}{2}\) via dem LaTeX-Code $K = \frac{mv^2}{2}$
Die Keyyboard Shortcuts sind in den Menüs neben den Auswahlen angegeben. Hier eine persönliche Auswahl:
Shortcut
Effekt
Ctrl+s
save notebook
Ctrl+Shift+q
close and shutdown notebook
Ctrl+f
Find
Enter
enter edit mode
Escape
enter command mode
Ctrl+Enter
run cell
Shift+Enter
run cell and got to cell below
Alt+Enter
run cell and insert a new cell below
Ctrl+b
toggle left sidebar
Shift+m
merge selected cells
in edit mode: Ctrl+Shift+-
split cell
in command mode: m
set cell type to markdown
in command mode: y
set cell type to code
in command mode: d d
delete cell
in command mode: z
undo deleting of cell
in command mode: a
insert cell above
in command mode: b
insert cell below
in command mode: x/c/v
cut/copy/paste cells
in command mode: UP/DOWN arrow
selected previous/next cell
in command mode: i+i
interrupt kernel
in command mode: 0+0
restart kernel
in command mode: Shift+l
toggle all line numbers
Bevor Sie JupyterLab beenden, vergessen Sie nicht, Ihre Jupyter-Notebooks zu speichern, zu schließen sowie die zugehörigen Kernel herunterzufahren. Zum Beenden von JupyterLab wählen Sie im Menü File/Shut Down.
Exportieren: Sie könne Jupyter-Notebooks über den Menüeintrag File/Export Notebook As oder über Systembefehle in andere Dateiformate exportieren. Systembefehle können Sie in einem System-Terminal, im Anaconda Command Prompt ausführen, oder in einer Codezelle, wenn Sie ein Rufezeichen vor den Systembefehl setzen. Hier eine Auswahl:
Unter nbconvert finden Sie die Syntax für noch weitere Outputformate und Infos zu evtl. Zusatzsoftware, die für die Konvertierung notwendig ist.
Hinweis: Um Ihren Code bei Bedarf außerhalb der JupyterLab-Umgebung auszuführen, können Sie
Ihr Jupyter-Notebook mynotebook.ipynb in ein Python Script mit Endung .py exportieren und anschließend von einem System-Terminal aus mit python mynotebook.py starten oder
in einem System-Terminal jupyter nbconvert --to notebook --execute mynotebook.ipynb verwenden.
Navigationsbefehle im Dateisystem: Für die Arbeit in einem System-Terminal, dem Anaconda Command Prompt oder in einer Codezelle sind oft folgende Navigationsbefehle nützlich:
pwd: print working/current directory
ls oder dir: list files in current directory
cd DIR: change into absolute or relative directory DIR
Einführung in Python: Sollten Sie noch keine Erfahrung mit Python haben, dann können Sie zum Beispiel das folgende Tutorial als Einstieg verwenden.
Tutorial
Die folgende Einführung in Python für wissenschaftliches Rechnen lehnt sich stark an die Kapitel 1 bis 4 des empfehlenswerten Buchs “Programming for Computations - Python. A Gentle Introduction to Numerical Simulations with Python 3.6.” von Svein Linge und Hans Petter Langtangen, 2. Auflage, 2020, an.
Hier ein erstes Beispiel: Der Code unten berechnet die Höhe \(y(t) = v_0 t - \frac{1}{2}gt^2\) eines Balls zum Zeitpunkt \(t \geq 0\), der zum Zeitpunkt \(t=0\) aus der Höhe \(y = 0\) mit der Geschwindigkeit \(v_0\) vertikal in die Höhe geworfen wird.
Beachten Sie:
Code-Kommentare beginnen mit dem Rautezeichen #.
Funktionen haben immer runde Klammern.
Das Potenzieren von Zahlen wird mit ** implementiert.
# program for computing the height of a ball in vertical motionv0 =5# initial velocity in m/sg =9.81# acceleration of gravity in m/s^2t =0.6# time in sy = v0*t -0.5*g*t**2# vertical position in mprint(f"At time t = {t} s the ball is at height y(t) = {y} m.") # formated printing
At time t = 0.6 s the ball is at height y(t) = 1.2342 m.
Um Funktionen außerhalb der Python Standard Library, in der sich z. B. die Funktion print befindet, zu verwenden, importieren wir die gewünschten Python Pakete in den Namespace unseres Jupyter-Notebooks. Die Pakete NumPy und Matplotlib verwenden wir unter anderen in der Lehrveranstaltung.
# imports into the namespace:import numpy as npimport matplotlib.pyplot as plt
Die Funktionen und Module des Pakets numpy können nach dem obigen Import mit np.* angesprochen werden. Analoges gilt für die Funktionen von matplotlib.pyplot.
Mit NumPy können wir die Berechnung der vertikalen Position des Balls vektorisieren, und mit Matplotlib können wir diese grafisch darstellen.
t = np.linspace(0, 1, 42)y = v0*t -0.5*g*t**2plt.plot(t, y, '.-m') # plots all y coordinates vs. all t coordinatesplt.xlabel("t (s)") # places the text t (s) on x-axisplt.ylabel("y (m)") # places the text y (m) on y-axisplt.grid(True)
Jetzt aber der Reihe nach!
Import von Paketen
Anstatt das gesamte Paket some_package mit import some_package as some_prefix mit einem selbstgewählten Präfix some_prefix zu importieren, können auch einzelne Funktionen importiert werden.
from numpy import linspace, pi# after the import linspace and pi are part of the namespace, e. g.:linspace(0, 5, 11)
Achtung: Es ist nicht empfohlen, alle Funktionen und Module eines Pakets mit einem Import vom Typ from math import * in den Namespace zu importieren! Warum?
Datentypen - eine Auswahl
Von den integrierten Datentypen verwenden wir die unten angeführten. Dabei besprechen wir deren Funktionalitäten nicht vollständig!
String: immutable
x ="Hello World"# or 'Hello World'print(type(x))print("Applied "+"Mathematics") # adding is concatenating
<class 'str'>
Applied Mathematics
Integer: immutable
x =42print(type(x))
<class 'int'>
Float: immutable
# float is short for floating point numberx =42.123456789print(type(x))
<class 'float'>
print(type(12/3)) # result is of type float
<class 'float'>
print(4/4*3)print(4/(4*3)) # do not forget the brackets if you wanted this.
# A list is a collection which is ordered and changeable (= mutable).x = ['Eric', 42, 0.3]print(type(x))print(len(x)) # length, i. e. number of items, of the list
<class 'list'>
3
# accssing list items:print(x[0]) # Python starts counting with 0!print(x[1:3]) # item with index 1 included, item with index 3 excluded!print(x[:2]) # items up to index 2 excludedprint(x[1:]) # items starting from index 1 includedprint(x[-1]) # last itemprint(x[-2]) # second last itemprint(x[-2:]) # from the end up to second last item included print(x[-2:-1]) # should be clear now
# A tuple is a collection which is ordered and unchangeable (= immutable).x = ('Eric', 42, 1/3)print(type(x))print(x[1])# But x has for example no append method.# you can make it a list with list(x)
<class 'tuple'>
42
['Eric', 42, 0.3333333333333333]
Dictionary: mutable
A dictionary allows you to map arbitrary key values to pieces of data. Any immutable Python object can be used as a key: an integer, a floating-point number, a string, or even a tuple.
Achtung! Zu den unveränderlichen (immutable) Objekten zählen integers, floats, strings und andere, während Numpy Arrays (siehe unten) und Listen Beispiele für veränderliche (mutable) Objekte sind. Das hat folgende wichtige Auswirkungen:
x =1y = xy =4print(x)
1
# however:x = [1,2,3]y = x # Python creates a reference to the mutable object xy[0] =4print(x)
[4, 2, 3]
# workaround with copying values:x = [1,2,3]y = x.copy() # Python creates a new object yy[0] =4print(x)
[1, 2, 3]
NumPy Arrays, short arrays: mutable
1-dimensionale Arrays für Vektorrechnung
2-dimensionale Arrays für Matrizenrechnung
x = np.array([1, 2.1, -5])print(x)print(type(x))print(len(x)) # length, i. e. number of itemsprint(np.ndim(x)) # number of dimensions
[ 1. 2.1 -5. ]
<class 'numpy.ndarray'>
3
1
# accssing list items works the same as with lists:print(x[0]) # Python starts counting with 0!print(x[1:3]) # item with index 1 included, item with index 3 excluded!print(x[:2]) # items up to index 2 excludedprint(x[1:]) # items starting from index 1 includedprint(x[-1]) # last itemprint(x[-2]) # second last itemprint(x[-2:]) # from the end up to second last item included print(x[-2:-1]) # should be clear now
# The thing about copying ... :x = np.array([1,2,3])y = xy[0] =4print(x)x = np.array([1,2,3])y = x.copy()y[0] =4print(x)
[4 2 3]
[1 2 3]
# 2-dim arrays, aka matricesM = np.array([[1,2,3], [4,5,6]])print(M)print(np.ndim(M)) # number of dimensions, number of square bracketsprint(M.shape) # number of rows and number of columns
[[1 2 3]
[4 5 6]]
2
(2, 3)
# accessing items and slices:print(M[1,2])print(M[1,:])print(M[:,0])print(M[:,[0]])
6
[4 5 6]
[1 4]
[[1]
[4]]
Overview of mutable and immutable data types:
mutable data types: list, dictionary, array, …
immutable data types: int, float, bool, string, tuple, …
Formatiertes Drucken
Wir verwenden “f-strings” für das formatierte Drucken. Zwei weitere Methoden werden z. B. im Buch von Linge und Langtangen beschrieben. f-strings beginnen mit einem f vor den Anführungszeichen, die den string kennzeichnen. Variablenwerte werden geschwungenen Klammern eingebunden. Zeichenketten (=strings), die über mehrere Zeilen laufen, können mit dreifachen Anführungszeichen geschrieben werden. \n bewirkt eine neue Zeile im Ausdruck. Mehr zu f-strings finden Sie z. B. im Python f-string tutorial.
my_name ="Klaus"my_age =47my_float =123.123456789print(f"Hallo! My name is {my_name}.")print(f"Two of my objects:\n{my_name =}\n{my_age =}.") # self-documenting expressionprint(f"I am {my_age} years old. These are about {my_age*365} days.")print(f"""My number in different formats:{my_float:.3f} or{my_float:10.3f} or{my_float:.3e} or{my_float:10.3e}""")
Hallo! My name is Klaus.
Two of my objects:
my_name = 'Klaus'
my_age = 47.
I am 47 years old. These are about 17155 days.
My number in different formats:
123.123 or
123.123 or
1.231e+02 or
1.231e+02
Grafiken
Wir werden nur wenige Beispiele in diesem Abschnitt aufzeigen. Die große Vielfalt an grafischen Darstellungsmöglichkeiten mit dem Python-Paket Matplotlib finden Sie z. B. unter Matplotlib Gallery. Es gibt neben Matplotlib noch viele andere Grafik-Pakete. Interaktive Grafiken können Sie z. B. mit ipywidgets erstellen.
# set default values for all plotting:plt.rcParams['axes.titlesize'] =14plt.rcParams['axes.labelsize'] =14plt.rcParams['xtick.labelsize'] =14plt.rcParams['ytick.labelsize'] =14plt.rcParams['legend.fontsize'] =12plt.rcParams['lines.linewidth'] =2
x = np.linspace(-1, 3, num =11)y =-x**2+8plt.figure(figsize=(8,5))plt.plot(x, y, 'o-g', label='Parabel')plt.xlabel('Weite $x$ (m)')plt.ylabel('Höhe $y$ (m)')plt.ylim(-2, 10)plt.title('Parabel')plt.legend(numpoints=1, loc='best')plt.grid(True)plt.savefig('abbildungen/Parabel.pdf')
t = np.linspace(-2, 2, 100)f_values = t**2g_values = np.exp(t)plt.figure(figsize=(8,5))plt.plot(t, f_values, 'r', t, g_values, 'b--')plt.xlabel('t')plt.ylabel('f and g')plt.legend(['$f(t) = t^2$', '$g(t) = e^t$'])plt.title('Plotting of two functions ($t^2$ and $e^t$)')plt.grid(True)plt.axis([-3, 3, -1, 10]);
Kontrollstrukturen
for-Schleife: hat die Struktur
for loop_variable in iterable_object:<code line 1><code line 2> etc.# first code line after the loop
# example 1: iteration over a listfor item in ["1", 2, np.pi]:print(item)
1
2
3.141592653589793
# example 2: iteration over an arrayv = np.linspace(0, 3, 7)for x in v:print(x, end=", ")
0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0,
# example 3: using enumerate to get the indices toomy_list= ['Sokrates', 'Platon', 'Aristoteles']for index, value inenumerate(my_list):print(f"{index +1}. {value}")
1. Sokrates
2. Platon
3. Aristoteles
# list comprehension:my_list_1 = [-x for x in np.arange(-3, 4)]print(my_list_1)my_list_2 = [-x for x in np.arange(-3, 4) if x <0]print(my_list_2)my_list_3 = [-x if x <0else x for x in np.arange(-3, 4)]print(my_list_3)
if condition_1: <code line 1><code line 2> ...elif condition_2: # optinonal<code line 1><code line 2> ...elif condition_3: # optinonal<code line 1><code line 2> ...else: # optinonal<code line 1><code line 2> ...# First line after if-elif-else construction
T =5# select a water temperature in degree centigradeif T <=20:print("Do not swim. Too cold!")elif T <=36:print("Great, jump in!")else:print("Do not swim. Too hot!")
Do not swim. Too cold!
Tipps: - Mit der break-Anweisung gelangen Sie direkt zur ersten Codezeile nach einer Schleife . - Mit der continue-Anweisung fahren Sie direkt mit der nächsten Iteration fort.
Funktionen
Eine Funktion hat die Struktur
def function_name(pos1, pos2, ..., kw1=default_1, kw2=default_2, ...): # function header"""This is a docstring"""# function body<code line># function body<code line># function body ... # function bodyreturn result_1, result_2, ... # last line in function body# First line after function definition
Die return Zeile, die die Rückgabewerte definiert und die Argumente pos1, ..., kw1 = ... sind jeweils optional. Eine Funktion kann daher auch so aussehen:
def my_function():"""function without arguments and without return values"""print("Ahoi!")
my_function()
Ahoi!
Der Doc-String ist der Hilfetext zur Funktion und kann aufgrund der dreifachen doppelten Anführungszeichen über mehrere Zeilen laufen.
help(my_function)
Help on function my_function in module __main__:
my_function()
function without arguments
and without return values
Argumente:
Die Argumente pos1, pos2, ... sind sogenannte positional parameters.
Die Argumente kw1, kw2, ... sind sogenannte keyword parameters.
Positional parameters müssen vor keyword parameters angeführt werden. Die Werte der Parameter, die beim Aufruf der Funktion übergeben werden heißen positional bzw. keword arguments. Die Werte default_1 und default_2 sind Default-Werte, die verwendet werden, wenn keine entsprechenden keyword arguments beim Aufruf der Funktion angegeben werden.
my_greet('Albert', 'Einstein') # my_greet('Albert', 'Einstein', msg='Good night!')my_greet('Albert', 'Einstein', 'Good night!')my_greet('Good night!', 'Albert', 'Einstein') # gives no error, but is not what you intended!my_greet(first_name="Albert", second_name='Einstein', msg="How do you do?")my_greet("Albert", second_name='Einstein', msg="How do you do?")my_greet(msg ="How do you do?", first_name="Albert", second_name='Einstein') my_greet(second_name='Einstein', first_name="Albert", msg ="How do you do?")# my_greet(msg="How do you do?", "Albert", "Einstein") # gives "SyntaxError: positional argument follows keyword argument"!
Hello Albert Einstein! Good morning!
Hello Albert Einstein! Good night!
Hello Albert Einstein! Good night!
Hello Good night! Albert! Einstein
Hello Albert Einstein! How do you do?
Hello Albert Einstein! How do you do?
Hello Albert Einstein! How do you do?
Hello Albert Einstein! How do you do?
Erkenntnisse:
Keyword arguments können auch ohne keyword angegeben werden.
Es ist möglich, die Namen von positional parameters als keywords zu verwenden.
Die Reihenfolge von keyword arguments kann geändert werden.
Eine Funktion kann mit positional oder mit keyword arguments oder aus einer Mischung aufgerufen werden. Bei der Mischvariante müssen die positional arguments jedoch zuerst angeführt werden müssen.
Solange in einem Funktionsaufruf für alle Argumente keywords verwendet werden, kann eine beliebige Reihenfolge der Argumente verwendet werden.
Geltungsbereich von Variablen (engl. Scope of Variables):
if"y"inlocals():del(y)
k =2# global variable defined in the main programd =100# global variable defined in the main programdef my_line_value(x):# The global variables k and d are known from "outside". k =10# k is now also the name of a local variable. # The assignment k = 10 changes only the local variable inside the function.# The "name-brother" global variable outside is not affected!print(f"inside values: k = {k}, d = {d}") y = k*x + d print(f"inside computation {y} = {k}*{x} + {d}")return yx =3print(f"outside values before function call: k = {k}, d = {d}")print(f"return value of input {x}: {my_line_value(x)}.")print(f"outside values after function call: k = {k}, d = {d}")# print(y) # gives "NameError: name 'y' is not defined"
outside values before function call: k = 2, d = 100
inside values: k = 10, d = 100
inside computation 130 = 10*3 + 100
return value of input 3: 130.
outside values after function call: k = 2, d = 100
Achtung: Veränderliche äußere Objekte werden in Funktionen geändert!
def my_plot(fct, start=-1, stop=3, legend=True): x = np.linspace(start, stop, num=100) y = fct(x) plt.plot(x, y, label=fct.__name__) plt.xlabel('x') plt.ylabel('y')if legend: plt.legend() plt.grid(True)
my_plot(np.sin, 0, 2*np.pi)
my_plot(lambda x: x - x**2, legend=False)
Daten IO
Es gibt sehr viele Arten Daten und Dateitypen. Wir beschränken uns hier auf das Laden und Speichern von einfachen CSV-Dateien. Als Beispiel nehmen wir die global temperature anomalies with respect to the 20th century average, genauer die dort bereitgestellte csv-Datei data.csv. Anstatt die Daten Zeile für Zeile einzulesen und zu parsen, verwenden wir das sehr mächtige und allen Data Scientists empfehlenswerte Paket pandas.
import pandas as pd
filepath ="daten/data.csv"df = pd.read_csv(filepath, skiprows=4, index_col=0) # read file into a pandas DataFramedf
Value
Year
1880
-0.09
1881
0.03
1882
-0.14
1883
-0.16
1884
-0.22
...
...
2016
0.95
2017
0.88
2018
0.82
2019
0.87
2020
0.95
141 rows × 1 columns
# We can directly plot the DataFrame ...df.plot(figsize=(8,6), grid=True, marker='.')plt.ylabel('°C');
# ... or we convert the data to data types we already know ...years = df.index.values # to numpy arrayvalues = df['Value'].values # to numpy array# ... and plot these:plt.figure(figsize=(8,6))plt.plot(years, values, '.-', label='Values')plt.xlabel('Year')plt.ylabel('°C')plt.legend()plt.grid(True)
# exporting data to files:# from DataFrame to Excel:my_filepath ="daten/data_exported_with_pandas.xlsx"df.to_excel(my_filepath) # from numpy array to csv:my_filepath ="daten/data_exported_with_numpy.csv"np.savetxt(my_filepath, values, delimiter=',') # using numpy