Tutorial 1 - Intro Python

Python ist eine Programmiersprache, die zugleich einfach und mächtig ist und welche die Spass macht. Die ersten beiden scheinen sich zu wiedersprechen und der dritte Punkt trifft in der Regel nicht auf Programmiersprachen zu. Nach einigen Jahren programmieren kann ich alle Puntke voll und ganz bestätigen. Dieses Tutorial soll Python als wirkungsvolles Tool vermitteln und nicht eine Programmiersprache.

Falls du einen allgemeinen Einstieg in Python lesen möchtest, empfiehlt sich A Byte of Python von Swaroop. Dieses Buch gibt es auch online in deutscher Version. Er zietiert auch Wendte mit: "Erfolg im Leben ist eine Sache, die weniger mit Talent und Gelegenheit zu tun hat, als mit Konzentration und Beharrlichkeit."

Viel Spass! Markus Markstaler.

Installation

Der schnellste Weg um Python zu installieren ist über die Anaconda-Plattform, welches Python mit den wichtigsten Paketen (Libaries) enthält, sowie die Entwicklungsumgebung "Spyder" als Editor um Scribt-Files zu erstellen. (Internetsuche "anaconda python") Bei der Installation beachten das "Add Anaconda to my PATH enviroment variable" angekreuzt wird. Somit kann über das Command-Window python.exe in jedem Verzeichnis gestartet werden. Die Systemumgebungsvariabel (enviroment variable) kann auch nachträglich erweitert werden um den VERZEICHNISNAMEN, wo python.exe abgelegt ist (z.B. C:\Anaconda3) durch folgenden Befehlt im Command-Window:

path=%path%;VERZEICHNISNAMEN

Bei Python gibt es grundsätzlich zwei Version: die 2.x und die 3.x. Natürlich verwenden wir die Neue Version! Die 2.x ist aber nach wie vor sehr verbreitet.

Pakete: Zusätzliche (zu den bereits mitinstallierten) Pakete können über das Kommando-Window (cmd) mit dem Befehl conda install <Paketname> installieren, wobei <Paketname> durch den Namen des Pakets zu ersetzen ist. Anconda enthält jedoch alle, für uns notwendigen Pakete. Sie können die installierten Pakete im Kommando-Window mit folgenden beiden Befehlen updaten:

  1. conda update conda
  2. conda update anaconda

Lets start

Nun starten wir die Entwicklungsumgebung "Spyder" für Python (windowstaste dann Spyder eingeben oder bei Mac nach "Spyder" suchen). Das müsste dann so aussehen:

Starten von Spyder und Befehl in Konsole eingeben

Wie bei allem was mit Computer zu tun hat, geben wir nach dem Starten von "Spyder" in die Konsole (IPython console) ein Befehl ein. Die Konsole ist auch unser Python-Interpreter. Gib folgendes ein:

In [1]:
print('Hello World!')
Hello World!

Es wird der String ausgegeben. Ein String ist gekennzeichnet durch "doppeltes Hochkomma" oder 'einfaches Hochkomma', was gleichbedeutend ist. Bei drei Hochkommas kann der Text über mehrere Zeilen geschrieben werden und im Text können Hochkommas verwendet werden.

In [2]:
a = 12
In [3]:
print(a * 3 + abs(-0.2))
36.2

Die Variablen können auch in einem eigenen Fenster dargestellt werden, dem "Variable explorer". Dieser wird wie folgt geöffnet:

Variablen über Variable Explorer anzeigen

Tutorial 1 - Übung 1: Mathematische Funktionen in Python

Nun werden einige mathematische Funktionen vorgestellt. Zuerst die Division:

In [4]:
35/4
Out[4]:
8.75

So wird eine Ganzzahl-Division ausgeführt:

In [5]:
35//4
Out[5]:
8

Hier die Modulo-Funktion oder auch "Rest" genannt:

In [6]:
35 % 3
Out[6]:
2

Potenziert wird in Python mit **

In [7]:
2**3
Out[7]:
8

Im gleichen Stil kann auch so die Kubik-Wurzel geschrieben werden:

In [8]:
27**(1/3)
Out[8]:
3.0

Im Folgenden werden zwei Variablen definiert und geprüft ob sie gleich sind. Jede Zeile wird einzel eingegeben und mit Enter abgeschlossen:

In [9]:
a = 5
b = 6
a == b
Out[9]:
False
In [10]:
a != b
Out[10]:
True

Logik-Operatoren sind

"&" für bitweises UND,

"|" für bitweises ODER und

"~" für bitweises NICHT.

Energierechnungen basieren in der Regel auf Zeitreihen, z.B. Strahlungswerte über einen Tag im Intervall von 15 min. Python bietet hier "Liste". Eine Liste beginnt und endet mit eckigen Klammern [].

In [11]:
H = [0, 10, 120, 230, 430, 500, 510,]

Tutorial 1 - Übung 2: Bibliotheken importieren

Mit Anaconda sind bereits die wichtigsten Bibliotheken installiert. Wir verwenden zum Rechnen die "numpy" Bibliothek. Um sie anwenden zu können, müssen wir zuerst die Bibliothek importieren. Dies erfolgt mit 'import numpy'. Numpy ist eine Bibliothek mit vielen numerischen Funktionen, wie z.B. die Absolut-Funktion abs(). Wenn wird diese später aufrufen wollen, müssen wir zuerst den Bibliotheksnamen dann Punkt und dann den Funktionsnamen angeben "numpy.abs(-3)". Da dies etwas lang ist importieren wir wie folgt "import numpy as np", dann müssen wir später nur "np.abs(-3)" angeben.

In [12]:
import numpy as np

Nach Eingabe sieht man nichts auf der Konsole. Mit dir(Bibliotheksname) können alle Funktionen (aber auch Klassen und Variablen) der importierten Bibliothek aufgelistet werden. Die importierten Bibliotheken sind nun aktive bis Spyder wieder geschlossen wird.

Liste ermöglicht auch unterschiedliche Elemente wie String, Zahlen, usw.. Wir werden aber vektoriell rechnen, was ebenfalls durch numpy unterstützt wird, jeodoch müssen wir die Liste (nur mit Zahlen) in ein "numpy-Array" umwandeln. Dies geht so:

In [13]:
Hn = np.array(H)
In [14]:
Hn.shape
Out[14]:
(7,)

"shape" gibt die Form der Matrix an, d.h Anzahl Zeilen und Anzahl Spalten. Hier haben wir einen eindimensionalen Array.

Wie wir gelernt haben, wird eine Liste mit eckigen Klammern erzeugt. Werden eckige Klammern nach dem Variablennamen einer Liste oder eines Numpy-Array gesetzt, kann man auf die Elemente zugriefen. Man nennt dies "Indexierung". Die Indexierung beginnt bei 0 nicht bei 1, d.h. das erste Element ist Hn[0] ! Im Folgeden werden Befehle eingegeben und anschliessen mit Kommentar erklärt. Der Kommentar wir mit Doppelkreuz # angegeben. Eingabe des Kommentar ist nicht erforderlich, sondern hier nur als Erklärung.

In [15]:
Hn[3] # das ist das vierte Element
Out[15]:
230
In [16]:
Hn[-1] # Das ist das letzte Element
Out[16]:
510
In [17]:
Hn[3:5] # Hier von Index 3 (viertes Element) bis und mit Index 4, ohne Index Fünf.
Out[17]:
array([230, 430])
In [18]:
Hn[3:-2]  # auch hier wird zweitletzter Index nicht mit genommen
Out[18]:
array([230, 430])
In [19]:
Hn[3:-1]  # hier wird bis zum zweitletzten Element übernommen, ohne den letzten Index
Out[19]:
array([230, 430, 500])
In [20]:
Hn[3:]  # Hier wird bis und mit letztem Element übernommen
Out[20]:
array([230, 430, 500, 510])

Tutorial 1 - Übung 3: Ausführbare Programme, bzw. Skript-Files

Die Befehle können wir in ein File schreiben und als Skript laufen lassen. Das File wird mit der Endung *.py gespeichert. Den Inhalt des Files schreiben wir im linken Fenster bei "Spyder", genannt der Editor. Im Folgenden importieren wir Numpy und die Bibliothek zum Erstellen von Diagrammen "Matplotlib" oder genauer gesagt aus der Hauptbibliothek "Matplotlib" importieren wir die Bibliothek "pyplot", worin die Diagramm Befehle sind. Wir definieren wieder einen Array und stellen diesen als Diagramm dar. Nachdem wir das Script-File erstellt und gespeichert haben, können wir dies mit der grünen Dreiecks-Taste oben links "laufen" lassen, oder wir drücken die F5-Taste.

In [21]:
### importieren von Bibliotheken
import matplotlib.pyplot as plt
import numpy as np

H = [0, 10, 120, 230, 430, 500, 510, 460, 310, 190, 80, 1,]
Hn = np.array(H)

### Ausgabe
plt.plot(Hn, 'r--', label='Strahlung')
plt.ylabel('Strahlung [W/m2]')
plt.title('Tagesverlauf Globalstrahlung')
plt.show()
<Figure size 640x480 with 1 Axes>

Das Diagramm wird mit "plot" generiert. Mit 'r--' wird die Linienfarbe und Linienart angegeben. Mit "label" wird der Name der Kennlinie angegeben, welcher nachfolgend über "legend" dargestellt wird. Der Befehl "grid" zeichnet die Hilfslinien ins Diagramm.

Nun erzeugen wir einen Zeit-Array von 6 bis 19 Uhr. Der Zeitarray sollte gleich viele Elemente haben wie der Strahlungs-Array Hn. Die Länge des Strahlungs-Arry finden wir mit Hn.size heraus. Um einen Numpy-Array zu erzeugen werden wir die Funktion linspace(start,stop, AnzahlElemente).

Du kannst das bestehende Skript-File mit den folgenden Aufgaben abändern und ausprobieren. Es ist nicht notwendig für jede Übung ein eigenes Skript-File zu erstellen und speichern.

In [22]:
### importieren von Bibliotheken
import matplotlib.pyplot as plt
import numpy as np

H = [0, 10, 120, 230, 430, 500, 510, 460, 310, 190, 80, 1,]
Hn = np.array(H)
tn = np.linspace(6, 19, Hn.size)

### Ausgabe
plt.plot(tn, Hn, color='#aa5500', linewidth=3, label = 'Strahlung')
plt.xlabel('Zeit')
plt.ylabel('Strahlung [W/m2]')
plt.grid()
plt.legend(loc='upper left')
plt.show()

Die Linienfarbe kann auch als RGB-Wert in Hex angegeben werden, durch "color = #aabbcc". Ebenso die Stärke der Linie über "linewidth".

Tutorial 1 - Übung 4: Wichtige Details...

In [23]:
# -*- coding: utf-8 -*-
"""
Es empfiehlt sich am Anfang kurz zu beschreiben was das Skript macht...
24.2.2017, Markstaler
"""

### importieren von Bibliotheken
import matplotlib.pyplot as plt
import numpy as np


### Berechnung
grad = np.linspace(0,360,200)  # [°]
amp  = np.sin(grad/180*3.1415) # [1]

### Ausgabe
fig = plt.figure(1, figsize=(5,3))
plt.plot(grad,amp, 'b-')
plt.xlabel('Grad')
plt.ylabel('Sinus')
plt.title('Sinusfuntion über Grad äöüß')
plt.grid(which='both', linestyle='--')
plt.show()

Nun sind da einige neue Funktionalitäten. In der ersten Zeile steht " # -- coding: utf-8 -- ". Bei Python können "magische" Kommandozeilen angegeben werden, sodass der Python-Interpreter den richtigen Zeichensatz verwendet. Standardmässig ist der ASCII-Satz vorgesehe, bei welchem die Umlaute und ß nicht enthalten sind. Dies führt zu einer Fehlermeldung (es lohnt sich dies auszuprobieren). Um die Kodierungsproblematik zu lösen, geben wir in der ersten Zeile an, dass der UTF-8-Code verwendet werden soll.

Anschliessend kommt ein Kommentar über mehrere Zeilen durch drei Hochkommas zur Dokumentation was das Skript macht. Anschliessend werden Bibliotheken importiert und eine Sinuskurve berechnet. Die Sinus-Funktion bei Numpy erfordert die Eingabe im Bogenmass (Radiant), wir verwenden jedoch das Gradmass. Deshalb die Umrechnung grad/80*3.1415.

Mit "fig = plt.figure(1, figsize=(5,3))" erzeugen wir ein Figure-Objekt. Das ist ein Blatt Papier nehmen und die Achsen aufzeichnen mit einer bestimmten Grösse, angegeben mit "figsize=(5,3)".

Wenn wir das Script-File unter "sinus.py" abspeichern, so können wir das Programm wie folgt startet. Wir öffnen das Kommando-Window (Windowstaste+cmd) und wechseln in das Verzeichnis, wo "sinus.py" abgelegt ist. Wir geben in das Kommando-Window "python sinus.py" ein.

Das Programm bleibt so lange offen, bis das Fenster wieder geschlossen wird.

Lambda-Operator

Mit dem Lambda-Operator können Funktionen definieren. Der Aufbau ist wie folgt am Beispiel $y = {b}^{e}$ als Funktion y = hoch(b,e) beschrieben.

In [24]:
hoch = lambda b, e : b ** e
In [25]:
hoch(2,3)
Out[25]:
8

Zuerst kommt der Funktionsname "hoch", ist gleich lambda. Nun weiss Python das hoch = keine Variabel ist, sondern dass eine Funktion definiert wird. Es folgen die Argumente getrennt duch Komma, anschliessend ein Doppelpunkt und der Ausdruck für die Berechnung. Vorteil des Lambda-Operator ist eine kompakte Schreibweise.

Für die Sonnenstandsberechnung benötigen wir Trigonometrische Funktionen (Sinus, Kosinus,...). Diese Funktionen sind in der numpy Bibliothek enthalten, jedoch rechnen diese mit Radiant und wir werden über Grad rechnen. Um nicht jedesmal umrechnen zu müssen, bauen wir uns eine eigene Funktionen mit Grad über den Lambda-Operator:

In [26]:
cos  = lambda arg : np.cos(np.deg2rad(arg))
sin  = lambda arg : np.sin(np.deg2rad(arg))
acos = lambda arg : np.rad2deg(np.arccos(arg))
asin = lambda arg : np.rad2deg(np.arcsin(arg))

Tutorial 1 - Übung 5: 3D Plot

Variieren wir nicht einen Parameter, sondern einen zweiten Parameter, so lässt sich das Ergebnis als 3D-Plot darstellen. Dies wird über die Funktion "plot_surface" realisiert. Für die Farbdarstellung importieren wir cm (colormap). Im Folgenden Beispiel wird "cm.Blues" verwendet. Es wird "LinearLocator, FormatStrFormatter" für die Achsenformatierung importiert. Beim untenstehenden Code wird eine Beispiel-Funktion gewählt, welche ein Eintdruck vermitteln soll was mit 3D-Plot möglich ist.

In [27]:
# -*- coding: utf-8 -*-
"""
Beispiel für ein 3D-Plot. Speichere das Skript ab als 3dplot.py und rufe es anschliessend 
über die Windows-Konsole (Windostaste>cmd) auf mit "python 3dplot.py". Es öffnet sich ein Fenster
mit dem 3D-Plot.
"""
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter

xArray=np.linspace(-2, 2,  90)
yArray=np.linspace(-2, 2, 110)

### Initialisierung, d.h. es werden Array mit Nullen (zeros) erzeugt
zMatrix = np.zeros((yArray.size, xArray.size))

for x in range(xArray.size):
    a = xArray[x]
    for y in range(yArray.size):
        b = yArray[y]
#…Berechnungscode….Anfang
        berechneteDaten = 500*a*b*np.exp(-a**2-b**2)
#…Berechnungscode….Ende

        zMatrix[y,x]= berechneteDaten            
    
fig = plt.figure(4, figsize=(8,4))
ax = fig.gca(projection='3d')
X, Y = np.meshgrid(xArray, yArray)
surf = ax.plot_surface(X, Y, zMatrix, \
                       rstride=1, cstride=1,\
                       cmap=cm.Blues, linewidth=0.2)
ax.set_xlabel('xArray')
ax.set_ylabel('yArray')
ax.set_zlabel('z-Achse')
ax.zaxis.set_major_locator(LinearLocator(5)) # Definiert Anzahl Teilstriche
ax.zaxis.set_major_formatter(FormatStrFormatter('%.f')) # Formatierung Zahl
fig.colorbar(surf, shrink=0.5, aspect=5)
ax.view_init(azim=29, elev=29)
plt.show()

Alternativ kann auch "Contour" als Plot verwendet werden:

In [38]:
fig = plt.figure(5, figsize=(8,6))
X, Y = np.meshgrid(xArray, yArray)
CS = plt.contour(X, Y, zMatrix, 15) # 15 Linien
plt.clabel(CS, inline=1, fontsize=10, fmt='%.f')
plt.title('Fantasiebeispiel einer Funktion')
plt.xlabel('x Achse')
plt.ylabel('y Achse')
plt.grid(which='both', linestyle='--')
plt.show()

Tutorial 1 - Übung 6: Einrücken !

Weitere wichtige Elemente beim Programmieren sind Möglichkeiten zur Steuerung des Programmflusses. Dies sind "if/elif/else" oder "while" mit "break" oder "continue". Sind diese Funktionen bekannt, einfach anwenden, Python ist hier intuitiv, ansonst nachlesen im Kapitel Control Flow im Buch A Byte of Python.

Was aber wichtig bei Python ist, dass ist das Einrücken. Dies wird am Beispiel einer for-Schleife erklärt, da sie für Energierechnungen notwendig sein kann, um einzelne Teilschritte zu berechnen. Die Folgenden Zeilen können im Skript-File eingegeben werden.

In [29]:
for i in range(2,5):
    print(i)
print('nun ist die for-Schleife zu Ende...')
print('...und es wird im Code fortgefahren')
2
3
4
nun ist die for-Schleife zu Ende...
...und es wird im Code fortgefahren

Alles innerhalb der for-Schleife wird bei jedem Durchlauf bearbeitet. Was zu for-Schleife gehört und was nach der for-Schleife kommt, erkennt python durch das Einrücken. Eingerückter Code gehört zur for-Schleife. Ist Einrückung fertig so weiss Python das dies nichtmehr zur Schleife gehört. Die for-Schleife führt Code-Sequenzen aus, wie hier "print(i)". Sie beinhaltet die Zählvariabel, welche hier "i" genannt wurde. Die Anzahl ist definiert mit "range(2,5)", d.h. es beginnt mit 1 bis ohne 5, in Ganzzahlschitten (nur Integer möglich). Dies liegt an der Python-Funktion range (siehe help(range)).

Verständlicher ist wenn, mit einem numpy-Array gearbeitet wird und dieser über linspace(start,stop, AnzahlElemente) erzeugt wird.

In [30]:
for s in ['Wahnsinn', 'was', 'mit', 'Python', 'alles', 'geht!']:
    print(s)
Wahnsinn
was
mit
Python
alles
geht!

Kopieren in Python

Stellt man sich einen Array als Kasten mit Schubladen vor, so lägen die Zahlenwerte in den einzelnen Schubladen. Als Beispiel ein Kasten mit Namen k und den Zahlen 1, 2, 3, 4, 5.

In [31]:
k = np.array((1, 2, 3, 4, 5))

Nun ist "k" nicht der Kasten, sondern das "Schildchen" wo auf den Standort des Kasten zeigt. Wir machen nun eine Kopie "a" von "k" und weisen dem letzen Element/Schublade den Wert 99 zu und sehen was passiert:

In [32]:
a = k
a[-1] = 9
print('a: ' + str(a))
print('k: ' + str(k))
a: [1 2 3 4 9]
k: [1 2 3 4 9]

Nun geben wir "k" aus und sehen dass auch dort das letzte Element geändert wurde! Dies liegt daran das wir nicht den "Kasten" kopiert haben, sondern das "Schildchen". Die Änderung haben wir aber beim Kasten gemacht, d.h. beide Schildchen zeigen auf den selben Kansten.

Um eine richtige Kopie zu machen, führen wir folgendes aus:

In [33]:
a = k.copy()
a[-1] = 6
print('a: ' + str(a))
print('k: ' + str(k))
a: [1 2 3 4 6]
k: [1 2 3 4 9]

In den folgenden Beispielen wird objektorientieres Programmieren nicht angewendet.

Hilfe

Zu den einzelnen Funktionen ist ein Hilfetext hinterlegt, welcher durch "help()" aufgerufen werden kann. Probiere mal "help(np.sqrt)".

Für allgemeine Hilfe zu Python verwendet man am Besten die Internetsuchmaschine und stellt die Frage. Es finden sich Reference-Manuals, Lernvideos, Forumseinträge, usw.

Beim Programmieren unterstütz der Editor die Fehlersuche durch Fehlermeldungen:

In [34]:
a = np.linspace(1,10,5)
b = np.linspace(1,10,10)
c = a + b
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-34-53ebf223a692> in <module>
      1 a = np.linspace(1,10,5)
      2 b = np.linspace(1,10,10)
----> 3 c = a + b

ValueError: operands could not be broadcast together with shapes (5,) (10,) 

Unklar sind die Fehlermeldung wenn ungleichviel Klammern geöffnet und geschlossen werden. Hier wird der Fehler bei der nachfolgenden Zeile angezeigt, welches verwirrend ist.

In [ ]:
b = (a + (2*a + 1)+ (3*a + 2)
c = a + b

Der zeite Fall von unklarer Fehlermeldung tritt bei Umlauten auf, kann aber durch die "magischen Kommandozeilen" gelöst werden.

In [ ]:
a = 10 # [m] Breite
b = 2  # [m] Höhe
c = 2*a + 2*b # [m] Umfang

Dieses IntroPython wurde mit Jupyter Notebook erstellt, welches ebenfalls in Anaconda-Paket enthalten ist. 14.3.2017, Markus Markstaler.

In [ ]: