Allgemeines

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:

Zu den Alternativen im Bereich wissenschaftliches Rechnen zählen

  • Julia: frei, offen und plattformunabhängig
  • R: frei, offen und plattformunabhängig
  • Matlab: kommerziell
  • Mathematica: kommerziell

Es gibt, grob gesagt, zwei Typen von Entwicklungsumgebungen:

JupyterLab

Starten Sie 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 beinhaltet 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.
  • Kommentare in Code-Zellen beginnen mit dem Rautezeichen #.
  • 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}$
  • Tipp: Cheatsheet

Keyboard Shortcuts

Die Keyboard Shortcuts (Tastenkürzel) 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:

  • HTML: Systembefehl jupyter nbconvert Mein_Notebook.ipynb
  • PDF: Systembefehl jupyter nbconvert --to pdf Mein_Notebook.ipynb
  • LaTeX: Systembefehl jupyter nbconvert --to latex Mein_Notebook.ipynb
  • Python-Script: Systembefehl jupyter nbconvert --to script Mein_Notebook.ipynb

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
  • cd ..: change to parent directory

Extensions: Folgende der vielen JupyterLab Extensions könnten Sie interessieren:

Tipps: Schauen Sie mal in die Gallery of interesting Jupyter Notebooks und in das Jupyter-Tutorial rein.

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 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 der Link zum Verlag.

Weitere nützliche Quellen:

Erste Schritte

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.
Code
# program for computing the height of a ball in vertical motion

v0 = 5     # initial velocity in m/s
g  = 9.81  # acceleration of gravity in m/s^2
t  = 0.6   # time in s

y = v0*t - 0.5*g*t**2  # vertical position in m

print(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.

Code
# imports into the namespace:
import numpy as np
import 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.

Code
t = np.linspace(0, 1, 42)  # creates an array of 42 numbers from 0 to 1

y = v0*t - 0.5*g*t**2

plt.figure(figsize=(5, 3)) # sets the size of the figure
plt.plot(t, y, '.-m')      # plots all y coordinates vs. all t coordinates
plt.xlabel("t (s)")        # places the text t (s) on x-axis
plt.ylabel("y (m)")        # places the text y (m) on y-axis
plt.grid(True)             # adds a grid to the figure

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.

Code
from numpy import linspace, pi

# after the import linspace and pi are part of the namespace, e. g.:
linspace(0, 5, 11)
array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ])
Code
from numpy import cos as cosinus

cosinus(pi)
-1.0

Für den Import von Paketen müssen nicht unbedingt Präfixe wie z. B. np vergeben werden.

Code
import numpy

numpy.linspace(0, 5, 11)
array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ])

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

Code
x = "Hello World"  # or 'Hello World'
print(type(x))
print("Applied " + "Mathematics") # adding is concatenating
<class 'str'>
Applied Mathematics

Integer: immutable

Code
x = 42
print(type(x))
<class 'int'>

Float: immutable

Code
# float is short for floating point number

x = 42.123456789
print(type(x))
<class 'float'>
Code
print(type(12/3)) # result is of type float
<class 'float'>
Code
print(4/4*3)
print(4/(4*3))  # do not forget the brackets if you wanted this.
3.0
0.3333333333333333
Code
# computations:

print(4.5 + 1.5)  # addition
print(4.5 - 5)    # subtraction 
print(2*7.1)      # multiplication
print(2**5)       # exponentiation
print(7.5/3)      # division
print(7.5//3)     # floor division, integer division
print(7.5%3)      # remainder, modulo
6.0
-0.5
14.2
32
2.5
2.0
1.5

List: mutable

Code
# 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
Code
# accessing 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 excluded
print(x[1:])    # items starting from index 1 included
print(x[-1])    # last item
print(x[-2])    # second last item
print(x[-2:])   # from the end up to second last item included 
print(x[-2:-1]) #  should be clear now
Eric
[42, 0.3]
['Eric', 42]
[42, 0.3]
0.3
42
[42, 0.3]
[42]
Code
# With the dot notation methods of the object can be accessed.
x.append(137)
x
['Eric', 42, 0.3, 137]
Code
# lists can also be added and multiplied:
x = ['Eric', 42, 0.3]
print(x + ['John', 137])
print(2*x)
['Eric', 42, 0.3, 'John', 137]
['Eric', 42, 0.3, 'Eric', 42, 0.3]

Tuple: immutable

Code
# 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.

Code
x = {"name" : "Eric",
     "age"  : 42}
print(type(x))
<class 'dict'>
Code
# accessing dictionary items:
x['name']
'Eric'

Boolean: immutable

Code
# boolean:

print(type(True))
print(type(False))
print(4 == 12/3)
print(4 >= 3)
print(4  < 3)
print(4 != 3)
print(42 in ['Eric', 42, 1/3])
<class 'bool'>
<class 'bool'>
True
True
False
True
True

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:

Code
x = 1
y = x
y = 4
print(x)
1
Code
# however:
x = [1,2,3]
y = x   # Python creates a reference to the mutable object x
y[0] = 4
print(x)
[4, 2, 3]
Code
# workaround with copying values:
x = [1,2,3]
y = x.copy()   # Python creates a new object y
y[0] = 4
print(x)
[1, 2, 3]

NumPy Arrays, short arrays: mutable

  • 1-dimensionale Arrays für Vektorrechnung
  • 2-dimensionale Arrays für Matrizenrechnung
Code
x = np.array([1, 2.1, -5])
print(x)
print(type(x))
print(len(x))     # length, i. e. number of items
print(np.ndim(x)) # number of dimensions
[ 1.   2.1 -5. ]
<class 'numpy.ndarray'>
3
1
Code
# 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 excluded
print(x[1:])    # items starting from index 1 included
print(x[-1])    # last item
print(x[-2])    # second last item
print(x[-2:])   # from the end up to second last item included 
print(x[-2:-1]) # should be clear now
1.0
[ 2.1 -5. ]
[1.  2.1]
[ 2.1 -5. ]
-5.0
2.1
[ 2.1 -5. ]
[2.1]
Code
# With the dot notation many methods be accessed. 
# Use the TAB-key after the dot to see them! Here' an example:
x.mean()
-0.6333333333333333
Code
# Arrays can also be added and multiplied, 
# but now in the sense of vector algebra!
Code
y = np.array([3, -1.9, 42])

x + y  # vector addition: elementwise!
array([ 4. ,  0.2, 37. ])
Code
print(x)
print(x + 100)   # adding a scalar to all elements
[ 1.   2.1 -5. ]
[101.  102.1  95. ]
Code
3*x   # multiplying a scalar to all elements
array([  3. ,   6.3, -15. ])

Das innere Produkt zweier Vektoren wird im Englischen oft “dot product” genannt.

Code
np.dot(x, y)
-210.99
Code
# alternatively with the @ operator:
x@y
-210.99
Code
np.cross(x, y) # cross product: only für vectors with 3 elements
array([ 78.7, -57. ,  -8.2])
Code
x*x   # caution: elementwise!
array([ 1.  ,  4.41, 25.  ])
Code
x/x   # elementwise!
array([1., 1., 1.])
Code
x**3  # elementwise!
array([   1.   ,    9.261, -125.   ])
Code
# constructors:

x = np.arange(start = 0, stop = 5, step=2)
print(x)

x = np.linspace(start = 0, stop = 5, num=11)
print(x)

x = np.zeros(4)
print(x)

x = np.ones(7)
print(x)
[0 2 4]
[0.  0.5 1.  1.5 2.  2.5 3.  3.5 4.  4.5 5. ]
[0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 1.]
Code
# The thing about copying ... :

x = np.array([1,2,3])
y = x
y[0] = 4
print(x)

x = np.array([1,2,3])
y = x.copy()
y[0] = 4
print(x)
[4 2 3]
[1 2 3]
Code
# 2-dim arrays, aka matrices

M = np.array([[1,2,3],
              [4,5,6]])

print(M)
print(np.ndim(M)) # number of dimensions, number of square brackets
print(M.shape)    # number of rows and number of columns
[[1 2 3]
 [4 5 6]]
2
(2, 3)
Code
# 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.

Code
my_name  = "Klaus"
my_age   = 47
my_float = 123.123456789

print(f"Hallo! My name is {my_name}.")
print(f"Two of my objects:\n  {my_name = }\n  {my_age = }.") # self-documenting expression
print(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.

Code
# set default values for all plotting:
plt.rcParams['axes.titlesize']  = 12
plt.rcParams['axes.labelsize']  = 12
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
plt.rcParams['legend.fontsize'] = 10
plt.rcParams['lines.linewidth'] = 1
Code
x = np.linspace(-1, 3, num = 11)        # 11 points between -1 and 3
y = -x**2 + 8

plt.figure(figsize=(5, 3))              # sets the size of the figure
plt.plot(x, y, 'o-g', label='Parabel')  # plots all y coordinates vs. all x coordinates
plt.xlabel('Weite $x$ (m)')             # sets the x-label
plt.ylabel('Höhe $y$ (m)')              # sets the y-label
plt.ylim(-2, 10)                        # sets the limits of the y-axis
plt.title('Parabel')                    # title of the figure
plt.legend(numpoints=1, loc='best')     # legend uses the label set in plt.plot
plt.grid(True)                          # adds a grid to the figure

plt.savefig('abbildungen/Parabel.pdf')  # saves the figure as pdf

Code
t = np.linspace(-2, 2, 100)
f_values = t**2
g_values = np.exp(t)

plt.figure(figsize=(5, 3))
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]);  # sets the limits of the x- and y-axis

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
Code
# example 1: iteration over a list
for item in ["1", 2, np.pi]:
    print(item)
1
2
3.141592653589793
Code
# example 2: iteration over an array

v = 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, 
Code
# example 3: using enumerate to get the indices too

my_list= ['Sokrates', 'Platon', 'Aristoteles']
for index, value in enumerate(my_list):
    print(f"{index + 1}. {value}")
1. Sokrates
2. Platon
3. Aristoteles
Code
# 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 < 0 else x for x in np.arange(-3, 4)]
print(my_list_3)
[3, 2, 1, 0, -1, -2, -3]
[3, 2, 1]
[3, 2, 1, 0, 1, 2, 3]

while-Schleife: hat die Struktur

while some_condition:
    <code line 1>
    <code line 2>
    etc.
# first code line after the loop
Code
# find the first data points nearest to zero:
x = np.linspace(-3, 3, num=100)
y = x**2 - 4

plt.figure(figsize=(5, 3))
plt.plot(x, y, '.-')
plt.xlabel('x')
plt.ylabel('y')

ind = 0  # staring index, proceed to increasing values
sign_change = False
while not sign_change:
    old_sign = np.sign(y[ind])
    ind += 1
    new_sign = np.sign(y[ind])
    if new_sign != old_sign:
        sign_change = True

print(f"y[{ind -1}] = {y[ind - 1]}")
print(f"y[{ind   }] = {y[ind    ]}")
plt.plot(x[ind - 1], y[ind - 1], 'or')
plt.plot(x[ind    ], y[ind    ], 'og')
plt.grid(True)
y[16] = 0.12213039485766775
y[17] = -0.12029384756657491

if-elif-else-Abfragen: hat die Struktur

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
Code
T = 5 # select a water temperature in degree centigrade

if 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 body
    return 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:

Code
def my_function():
    """function without arguments 
    and without return values"""
    print("Ahoi!")
Code
my_function()
Ahoi!

Der Doc-String ist der Hilfetext zur Funktion und kann aufgrund der dreifachen doppelten Anführungszeichen über mehrere Zeilen laufen.

Code
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.

Hier ein Beispiel:

Code
def my_greet(first_name, second_name, msg="Good morning!"):
    print(f"Hello {first_name} {second_name}! {msg}")
Code
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):

Code
if "y" in locals():
    del(y)
Code
k =   2  # global variable defined in the main program
d = 100  # global variable defined in the main program

def 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 y

x = 3

print(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!

Code
x = [1, 2]  # mutable object
print(f"outside value: {x = }")

def change(y):
    y[0] = 4
    print(f"inside value:  {y = }")

change(x)
print(f"outside value: {x = }")
outside value: x = [1, 2]
inside value:  y = [4, 2]
outside value: x = [4, 2]
Code
# Auch ohne Übergabe:

x = [1, 2]  # mutable object
print(f"outside value: {x = }")

def change():
    x[0] = 4
    print(f"inside value:  {x = }")

change()
print(f"outside value: {x = }")
outside value: x = [1, 2]
inside value:  x = [4, 2]
outside value: x = [4, 2]

Lambda Funktionen: sind eine Möglichkeit, auf kompakte Arte “Einzeiler”-Funktionen zu definieren.

Code
g = lambda x: x**2
# is equivalent to:
# def g(x):
#     return x**2

g(3)
9

Allgemeine Form einer Lambda Funktion:

function_name = lambda arg1, arg2, ... : <some_expression>

Funktionen als Argumente von Funktionen:

Code
def my_plot(fct, start=-1, stop=3, legend=True):
    x = np.linspace(start, stop, num=100)
    y = fct(x)
    plt.figure(figsize=(5, 3))
    plt.plot(x, y, label=fct.__name__)
    plt.xlabel('x')
    plt.ylabel('y')
    if legend:
        plt.legend()
    plt.grid(True)
Code
my_plot(np.sin, 0, 2*np.pi)

Code
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.

Code
import pandas as pd
Code
filepath = "daten/data.csv"
df = pd.read_csv(filepath, skiprows=4, index_col=0) # read file into a pandas DataFrame
df
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

Code
# We can directly plot the DataFrame ...

df.plot(figsize=(5, 3), grid=True, marker='.')
plt.ylabel('°C');

Code
# ... or we convert the data to data types we already know ...

years = df.index.values      # to numpy array
values = df['Value'].values  # to numpy array

# ... and plot these:

plt.figure(figsize=(5, 3))
plt.plot(years, values, '.-', label='Values')
plt.xlabel('Year')
plt.ylabel('°C')
plt.legend()
plt.grid(True)

Code
# 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