python
-Programm ausgeführtHier soll es hingehen: Auswertung von Praktikumsversuchen:
Versuch aus dem Fortgeschrittenen-Praktikum: Lebensdauer kosmischer Myonen
Eine Programmiersprache wie Python lässt sich nicht an einem Tag lernen.
Hier geben wir einen kurzen Überblick über die wichtigsten Konzepte.
Keine Angst: Zum Erstellen von Plots und für einfache Auswertungen muss man nicht viel Python können!
Die folgenden Beispiele kann man auf der Kommandozeile durch ausführen von
ipython
ausprobieren.
print('Hello, World!')
Sehr wichtig für die Leute, die mit euch Arbeiten und für euch zwei Wochen später, sind Kommentare, die erklären, was euer Code tut.
Alles was in Python hinter einem #
steht, wird nicht als Code betrachtet und dient als Kommentar.
# This just prints the traditional greeting to the console
print("Hello, World!")
Kommentare sollten nicht erklären, was der Code tut, sondern warum.
Kommentare, wie jeder andere Code, sollten auf englisch sein.
Man kann einem Objekt einen Namen geben:
a = 2
b = 3
Variablennamen können auch überschrieben werden:
a = 42
b = a
a = 0
b
print(None)
Funktionen, die 'nichts' zurückgeben, geben None
zurück:
print('test')
a = print('test')
print(a)
True and False
True or False
not True
None
oder leere Objekte verhalte sich wie False
, andere wie True
None or True
'Hallo' and True
Ganze Zahlen: 42
Kommazahlen: 3.14
Rechenoperatoren:
+
, -
, *
**
(Potenzieren: 2**3
→ 8
)/
(3 / 2
→ 1.5
)//
(Ganzzahldivision: 3 // 2
→ 1
)%
(Modulo-Operation, Divisionsrest: 7 % 4
→ 3
)x = 5
y = 3
x + y
Rechenoperationene können geklammert werden
a = 2 + 4 / 5 + 1
b = (2 + 4) / 5 + 1
c = (2 + 4) / (5 + 1)
print(a)
print(b)
print(c)
Vergleichsoperatoren geben True
oder False
zurück
==
, !=
>
, <
, >=
, <=
x < y
Mehrere Vergleichsoperatoren können in einem Ausdruck stehen:
c < b < a
c < a < b
Stehen in '
oder "
.
foo = 'foo'
bar = "bar"
Strings können mit +
konkateniert werden:
foo + " " + bar
Strings können mit *
vervielfacht werden
foo * 4
Strings können mit []
indiziert werden
foo[0]
Gedacht für mehrere Werte vom selben Typ.
names = ['foo', 'bar']
Listen können mit []
indiziert werdern
names[1]
Man kann Werte an Listen anhängen:
names.append('baz')
names
Negative Indizes (beginnend mit -1
), indizieren die Liste rückwärts
names[-1]
Man kann auch Teillisten indizieren.
names[Anfang:Ende]
liefert eine Teilliste mit den Werten von names[Anfang]
bis names[Ende-1]
:
names[1:3]
Listen werden mit +
zusammengeführt:
names + ['thing']
Listen können mit *
vervielfacht werden:
names * 3
Man kann die Liste auch erweitern:
names.extend(['quux'])
names
Listen sind veränderbar, man kann ihnen Werte zuweisen:
names[1] = 'new'
names
Mit in
prüft man, ob ein Wert in der Liste ist:
weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
'Mo' in weekdays
Gedacht für Werte mit unterschiedlichen Typen. Unveränderbar nach Erzeugung. Können wahlweise auch ohne Klammerngeschrieben werden (wenn es eindeutig ist).
tup = 5, 3
tup
a = 5
b = 3
a, b = b, a
print("a =", a)
print("b =", b)
tup[0]
tup[1] = 7
numbers = { 'one': 1, 'two': 2, 'three': 3 }
numbers['two']
Dictionaries sind extrem hilfreich, zum Beispiel um die gleiche Analyse für verschiedene Datensätze durchzuführen:
data = {'Cu': [1.1, 1.2, 1.3, 1.4], 'Fe': [0.7, 0.8, 0.9, 1.0]}
data['Cu']
Leere Dictionaries erstellt man z.B. mit der Funktion dict()
data = dict()
data
data["Fe"] = [1.1, 1.2, 1.3, 1.4]
data
data["Cu"] = [0.7, 0.8, 0.9, 1.0]
data
data["Au"] = [0.2, 0.3, 0.1, 0.5]
data
In der aktuellen Python-Version 3.6 entspricht die Reihenfolge der Einträge in Dictionaries der
Zuweisungsreihenfolge! In allen älteren Versionen war dies nicht der Fall und es kann sich auch
wieder ändern. $\Rightarrow$ Nicht auf die Reihenfolge der Dictionary-Einträge verlassen.
Mit Funktionen lässt sich Code leicht wiederverwenden. Eine Funktion nimmt Parameter, verarbeitet sie und gibt Ergebnisse zurück.
print('Hello!')
len([1, 2, 3, 4, 5])
Viele Funktionen haben mehrere Parameter, einige können sogar beliebig viele haben:
print(1, 2, 3, 4, 5)
Viele Funktionen haben optionale Parameter mit eigenem Namen, sogenannte "keyword arguments":
print(1, 2, 3, sep=', ')
Objekte haben auch Funktionen (nennt man Methoden):
s = 'test'
s.upper()
'foo bar baz'.split()
In IPython kann man wie folgt auf die Dokumentation einer Funktion zugreifen:
print?
Ansonsten findet man ausführliche Erklärungen in der offiziellen Dokumentation.
Die Zeilen eines Python-Programms werden nacheinander ausgeführt.
Sogennante Kontrollstrukturen erlauben es, den Ablauf zu steuern.
if
/elif
/else
: Je nach Bedingung unterschiedliche Befehle ausführena = 3
if a == 1:
# muss eingerückt werden, 4 spaces:
print('foo')
elif a == 2:
print('bar')
else:
print('baz')
while
-Schleifen: Wiederholen, solange ein bestimmter Ausdruck erfüllt ist.i = 0
while i < 5:
print(i)
i += 1
# there has to be a better way!
for
-Schleifen: Wiederholen für jedes Element (z.B. einer Liste)data = [10, 42, -1]
for x in data:
# Wir können auf das jetztige Element als "x" zugreifen
print(2 * x)
for i in range(5):
print(i)
for i in range(2, 5):
print(i)
for i in range(10, 3, -1):
print(i)
# Hatten wir weiter oben bei den Listen erstellt
weekdays
for day in weekdays:
print("Heute ist", day)
Zwei sehr nützliche Funktionen sind enumerate
und zip
for i, day in enumerate(weekdays):
print(day, " ist der ", i+1, ". Tag der Woche", sep="")
Was enumerate()
macht:
list(enumerate(weekdays))
english = ["foot", "ball", "goal"]
german = ["Fuß", "Ball", "Tor"]
for a, b in zip(english, german):
print(a, b)
Was zip()
macht:
list(zip(english,german))
Das obere würde man eher so machen:
translations = {
'foot': 'Fuß',
'ball': 'Ball',
'goal': 'Tor',
}
for e, g in translations.items():
print(e, g)
def
¶Bevor man eine Funktion verwenden kann, muss sie erst definiert werden.
Das wird wie folgt gemacht.
Mit dem Keyword return
kann man die Funktion beenden und Ergebnisse zurückgeben.
def add(x, y):
z = x + y
return z
add(2, 2)
Man kann auch mehrere Werte zurückgeben:
def divide(x, y):
return x // y, x % y
n, rest = divide(5, 3)
n, rest
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
factorial(4)
import
¶In Python kann man Programme in einzelne Module portionieren.
Es stehen bereits unglaublich viele Module für Python zur Verfügung. Gerade fürs wissenschaftliche Arbeiten ist eigentlich alles da was man braucht und noch viel mehr. Braucht man etwas aus einem anderen Modul, importiert man es:
import os
os.listdir()
Man kann auch nur einzelne Funktionen importieren:
from os.path import join
outputpath = "Plots"
join(outputpath, "fig1.pdf")
from module import *
importiert jede Funktion eines Moduls. Sollte auf Grund von möglichen Mehrfachbelegungen
nicht in größeren Programmen verwendet werden
from os.path import *
outputpath = "Plots"
if exists(outputpath):
print("Plots exists!")
Den Modulen können mit as
neue Namen gegeben werden
import os.path as pa
pa.join(outputpath, "fig1.pdf")
.py
python programm.py
.py
) kann man als Module benutzen. Liegt eine Datei test.py
im selben Ordner, so kann man import test
ausführen.Es folgt ein fertiges Python-Programm.
Speichert es als primes.py
ab und startet es aus dem Terminal mit python primes.py
.
def primes(max_num):
# Only primes smaller than max_num are calculated
is_prime = max_num * [True]
is_prime[0] = False
is_prime[1] = False
primes = []
# Sieve of Erathosthenes:
for i in range(2, max_num):
if is_prime[i]:
for j in range(2 * i, max_num, i):
# Multiples are not primes
is_prime[j] = False
primes.append(i)
return primes
print(primes(100))
Mit \
kann man in Strings besondere Anweisungen setzen:
'\n'
-> Zeilenumbruch'\t'
-> Tab'\\'
-> normales '\'
Wenn man viele '\'
schreiben muss (z.B. in LaTeX-Code), lohnt es sich diese Funktion mit dem Prefix r
auszuschalten:
print(r'\Huge\texttt{Python}')
Oft will man Werte oder andere Strings in einen String einsetzen.
Seit der Python Version 3.6 gibt es sogenannte f-strings (formatted strings) für String-Formatierung:
first_value = 42
second_value = 0
print(f"Erster Wert: {first_value}, Zweiter Wert: {second_value}")
Die Variablen in den {}
-Markierungen werden durch die Werte der entsprechenden
Variablen ersetzt.
f-strings haben viele fortgeschrittene Funktionen.
Man kann beispielsweise die gewünschte Genauigkeit für floats
angeben:
result = 3.2291421
print(f'Das Ergebnis ist {result:.2f}')
Man kann die Variablen in f-strings auch verschachteln.
Zum Beispiel kann man die Genauigkeit für floats
auch als Variable angeben:
result = 3.2291421
precisions = [1,2,3,4,5]
for precision in precisions:
print(f'Das Ergebnis ist {result:.{precision}f}')
Die f-strings sind eine lesbarere Variante einer allgemeineren Funktionalität,
der format()
-Methode:
first_value = 42
second_value = 0
'Erster Wert: {}, Zweiter Wert: {}'.format(first_value, second_value)
Die {}
-Markierungen werden durch die Parameter von format()
ersetzt.
format()
bietet noch einige weitere Möglichkeiten, wenn f-strings mal nicht reichen.
Man kann Parameter benennen und diese genauso formattieren wie in f-stings:
'Das Ergebnis ist {result:.2f} und damit kleiner als {four}'.format(result=3.2291421, four=4)
Will man {
oder }
im Text stehen haben (gut für LaTeX) geht das mit doppelten {{
oder }}
.
LaTeX sieht dann leider so aus:
print(r'\SI{{{:.4f}}}{{{:s}}}'.format(1.23456, r'\kilo\joule'))
Nur zur Demonstration einmal mit mehr Lücken (funktioniert so nicht in LaTeX wegen den Leerzeichen!):
print(r'\SI {{ {:.4f} }} {{ {:s} }}'.format(1.23456, r'\kilo\joule'))
Ausführliche Beispiele zur Benutzung von Format findet man z.B. in der offiziellen Dokumentation:
https://docs.python.org/3.1/library/string.html#format-examples
Sind nützlich, um Listen oder Dictionaries umzuwandeln oder zu erzeugen:
# Ursprüngliche Liste
list(range(5))
# List-Comprehension
[2 * x for x in range(5)]
# Ursprüngliche Liste
list(enumerate(weekdays))
# Dict-Comprehension
{num + 1: name for num, name in enumerate(weekdays)}
# Ursprüngliche Listen
print(list(range(3)))
print(list(range(4)))
# List-Comprehension mit verschachtelten Schleifen
[x + y for y in range(3) for x in range(4)]
# List-Comprehension mit verschachtelten Schleifen und Bedingung
[x + y for y in range(3) for x in range(4) if x % 2 == 0]
Einige Fehler macht man zu Anfang sehr häufig (und immer mal wieder).
Wenn man die Fehlermeldungen richtig zu lesen weiß, kann einem das viel Arbeit/Frust ersparen.
Das Wichtigste ist: Lest die Fehlermeldung und versucht sie zu verstehen!
IndentationError
:¶Die Fehlermeldung gibt die Zeile an in der Fehler auftritt (hier: line 8
)
und den Grund für den Fehler, häufig mit Erklärung (hier: IndentationError: expected an indented block
)
a = 5
b = 7
c = 9
if a <= b:
if c >= b:
# Zeile 8 müsste in dem if-Block eingerückt werden
print("a <= b und b >= c")
else:
print("a <= b und b >= c")
else:
print("a > b")
SyntaxError
¶Zeile in der der Fehler auftritt: line 6
Grund für den Fehler: SyntaxError: invalid syntax
Hier sogar mit Hinweis auf das fehlerhafte/fehlende Zeichen.
a = 5
b = 7
c = 9
# In Zeile 6 fehlte der Doppelpunkt ':' nach der Bedingung, um den If-Block einzuleiten
if a <= b
if c >= b:
print("a <= b und b >= c")
else:
print("a <= b und b >= c")
else:
print("a > b")
Die Fehlermeldung ist hier im ersten Moment nicht besonders hilfreich:
Zeile in der der Fehler auftritt: line 11
Grund für den Fehler: SyntaxError: invalid syntax
Stimmt nur zum Teil, denn in Zeile 11 ist alles in Ordnung und der eigentliche Fehler ist in Zeile 10.
In komplexeren Programmen ist das nicht mehr so einfach zu sehen wie hier,
deswegen ist es gut, wenn man dieses Verhalten schon mal gesehen hat.
a = 5
b = 7
c = 9
if a <= b:
if c >= b:
# In Zeile 10 fehlt eine Klammer zum Vergleich:
# d = ((a + b) / (a + c))/((a + b) / (a + c))
d = ((a + b) / (a + c)/((a + b) / (a + c))
print("a <= b und b >= c")
else:
print("a <= b und b >= c")
else:
print("a > b")
NameError
:¶Zeile in der der Fehler auftritt: ----> 7 if a <= n:
Grund für den Fehler: NameError: name 'n' is not defined
Fehlermeldung sieht etwas anders aus, liefert aber immer noch die gleichen Informationen.
a = 5
b = 7
c = 9
# Beim Schreiben des Codes vertippt (n anstelle von b),
# sodass a <= n statt a <= b ausgewertet wird, n ist jedoch nicht definiert
if a <= n:
if c >= b:
print("a <= b und b >= c")
else:
print("a <= b und b >= c")
else:
print("a > b")
IndexError
¶Zeile in der der Fehler auftritt: ----> 4 names[4]
Grund für den Fehler: IndexError: list index out of range
Fehlermeldung sieht etwas anders aus, liefert aber immer noch die gleichen Informationen.
names = ["Anna","Jan","Marie","Tim"]
# Die Liste hat vier Einträge, da der erste Index aber 0 ist ist der letzte Index 3
# der Index 4 der in Zeile 4 abgerufen wird überschreitet diesen Bereich
names[4]
KeyError
¶Zeile in der der Fehler auftritt: ----> 4 numbers["five"]
Grund für den Fehler: KeyError: 'five'
Fehlermeldung sieht etwas anders aus, liefert aber immer noch die gleichen Informationen.
numbers = {"one": 1 ,"two": 2,"three": 3,"four": 4}
# Analog zum Beispiel mit der Listen Index
# Der key "five" ist nicht in dem Dictionary vorhanden
numbers["five"]
Wenn an einem Fehler mehrere Funktionen beteiligt sind,
gibt die Fehlermeldung einen Traceback aus.
Dieser Fall ist eher die Regel, vorallem, wenn man Module verwendet.
Der Traceback zeigt die Reihenfolge aller Funktionsaufrufe, die
am Ende zu dem Fehler geführt haben mit dem letzten Aufruf ganz unten (most recent call last).
Zeilen die zum Auftreten des Fehlers führen:
Funktionsaufruf in Zeile 10:
---> 10 add_one_to_inverse_difference(x,y)
Ergebnis des Funktionsaufrufs ist das return
in Zeile 5 mit neuem Funktionsaufruf:
----> 5 return 1 + inverse_difference(a, b)
Ergebnis des 2. Funktionsaufrufs ist das return
in Zeile 2:
----> 2 return 1/(a - b)
Hier tritt der Fehler auf, da durch Null geteilt wird, wenn a und b gleich sind!
Grund für den Fehler: ZeroDivisionError: division by zero
def inverse_difference(a, b):
return 1/(a - b)
def add_one_to_inverse_difference(a, b):
return 1 + inverse_difference(a, b)
def add_2_to_inverse_difference(a, b):
return add_one_to_inverse_difference(a, b) + 2
x = 2
y = 2
add_one_to_inverse_difference(x,y)