7. Kurzeinführung in Python#

Lernziel ist es grundlegende Elemente von Python kennenzulernen:

  • Syntax

  • Datentypen

  • Datenstrukturen: Tupel, Listen, Dictionaries

  • Kontrollstrukturen: if, for, while

  • Funktionen

Es geht explizit nicht darum einen umfassenden Überblick über Python zu gewinnen, z.B. wird Objektorientierung größtenteils ausgelassen. Wir betrachten Python vor allem als Werkzeug, um Bibliotheken für Data Analytics wie numpy, pandas, scikit, tensorflow zu nutzen. Wir gehen davon aus, dass die Leser bereits Kenntnisse in einer Programmiersprache haben und die Nutzung von Python on-the-job erlernen. Die datengetriebenen Programmierstile der genannten Bibliotheken korrekt zu nutzen ist häufig konzeptionell schwieriger als die reine Adaption von Code in konventionellen Programmiermodellen z.B. von Java nach Python. Beispielsweise ist die Nutzung einer Schleife in Zusammenhang mit numpy oder pandas ein Warnsignal - man sollte noch mal prüfen, ob es nicht einen eleganteren Weg gibt.

Für umfangreichere Einführungen in Python siehe:

Referenzen:

7.1. Programmierumgebung#

Python ist eine interpretierte Programmiersprache - es ist kein Compile-Vorgang notwendig. Wir können direkt eine Quellcode-Datei ausführen, z.B. können wir in der Datei helloworld.py den folgenden Quelltext speichern:

print("Hello World")

Nun können wir diesen Direkt ausführen:

$ python3 helloworld.py
Hello World
$

Einer der Treiber für die Beliebtheit von Python ist die interaktive Ausführung in Jupyter Notebooks: Code, Ausgaben, Grafiken und erklärender Text stehen in einem Dokument. In diesem Kurs arbeiten wir mit Notebooks in Visual Studio Code. Die Umgebung richten Sie wie in der Anleitung zum Projekt-Repository beschrieben mit uv sync ein. Danach öffnen Sie eine .ipynb-Datei in VS Code und wählen rechts oben als Kernel die Umgebung .venv im Projektverzeichnis.

Jede Zelle wird mit Shift+Enter ausgeführt. Variablen bleiben über Zellen hinweg erhalten, die Reihenfolge der Ausführung zählt also, nicht die Reihenfolge im Dokument. Wenn sich ein Notebook seltsam verhält, hilft oft “Restart” und anschließend “Run All”.

Extrem hilfreich sind außerdem die folgenden Tastenkombinationen:

  • <TAB> für die Autovervollständigung von Variablennamen, Funktionsnamen, Methoden von Objekten usw.

  • <SHIFT>-<TAB> für Hilfe innerhalb der Klammern eines Funktionsaufrufs

Hilfe ist ebenso mit dem ? Operator möglich - das können Sie ausprobieren, wenn Sie z.B. den folgenden Code ausführen:

?print

7.2. Syntax#

Wir haben bereits kennengelernt:

  • Funktionsaufrüfe mit function_name(parameter)

  • Strings mit "Inhalt" Das führt uns zu:

print("Hello World")
Hello World

Strings können auch in einfachen Anführungszeichen stehen 'Hello World' und mehrere Strings mit + zusammengefügt werden.

'Hello ' + " World"
'Hello  World'

+ und andere Operationen funktionieren wie gewohnt für Zahlen, um Ausdrücke zu bilden, z.B.:

Operator

Beispiel

Ergebnis

-

5-2

3

+

5+2

7

/

22/8

2.75

*

3*5

15

**

2**3

8

Ein weiterer Erfolgsfaktor von Python ist die Lesbarkeit des Quellcodes. Dennoch ist nicht jeder Code selbsterklärend und der Leser des Codes - das ist man oft genug selber - freut sich über Kommentare, die mit # eingeleitet werden

# Das ist ein Kommentar

7.3. Datentypen#

Python ist dynamisch typisiert. Dies erlaubt uns Variablen ohne Typangaben zu erstellen und zu nutzen - ABER: es gibt Typen in Python und diese werden im Normalfall nicht automatisch konvertiert. Z.B.:

'3' + 3
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 '3' + 3

TypeError: can only concatenate str (not "int") to str
3 + '3'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[6], line 1
----> 1 3 + '3'

TypeError: unsupported operand type(s) for +: 'int' and 'str'

Weder wird ein String automatisch in eine Zahl konvertiert noch andersrum. Zwei Ausnahmen in einer Zeile:

print(2/3)
0.6666666666666666

Hier werden Ganzzahlen automatisch in Fließkommazahlen umgewandelt und die Zahl für print automatisch in einen String. Ansonsten ist Vorsicht angebracht:

'2' + '3'
'23'
'2' * 3
'222'

Oder explizite Konvertierungen sind angesagt:

int('2') * str(3)
'33'

Boolean#

Es ist existieren die 2 Konstanten True und False, ansonsten sind standardmäßig alle Objekte (das beinhaltet in Python auch Zahlen) true außer:

  • Numerische Typen mit dem Wert Null, z.B. 0, 0.0

  • Leere Sequenzen und Collections inklusive dem leeren String, z.B. ‘’, (), [], {}

  • Die Konstanten None und False

Die booleschen Operatoren sind or, and and not.

0 == 1
False
not 0 == 1
True

and and or liefern den letzten evaluierten Operanden zurück:

() or '' or [] or {}
{}
() and '' and [] and {}
()
1 or 0
1
True and False
False

7.4. Variablen#

Varablen können jederzeit ohne vorherige Deklaration durch die Zuweisung per = definiert werden:

a = 1
b = 2
c = a + b

Eine Zuweisung liefert keinen Wert zurück - das sehen wir in Jupyer Notebook (mit dem dieser Teil des Skripts entwickelt wurde) daran, dass es kein Out[ ] gibt. Wenn wir den Wert einer Variablen nach Zuweisung anzeigen wollen, müssen wir print verwenden:

print(c)
3

Oder wir erstellen einen Ausdruck, der einfach nur die Variable auswertet:

c
3

Variablen können fast beliebige Namen haben - die Groß-/Kleinschreibung wird berücksichtigt. Es gibt Ausnahmen:

  • Reservierte Wörter: and, as, assert, break, class, continue, def, del, elif, else, except, False, finally, for, from, global, if, import, in, is, lambda, None, nonlocal, not, or, pass, raise, return, True, try, with, while and yield.

not = 1
  Cell In[20], line 1
    not = 1
        ^
SyntaxError: invalid syntax
  • Namen, die mit einer Zahl anfangen:

123abc = "Hallo"
  Cell In[21], line 1
    123abc = "Hallo"
      ^
SyntaxError: invalid decimal literal
  • Namen mit Leerzeichen, stattdessen einfach einen Underscore _ verwenden:

echt langer Variablenname = 4
  Cell In[22], line 1
    echt langer Variablenname = 4
         ^
SyntaxError: invalid syntax
echt_langer_Variablenmame = 4
  • Nicht verboten aber nicht empfehlenswert: gemischte Kapitalisierung

variable_1 = 4
Variable_1 += 1
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[24], line 2
      1 variable_1 = 4
----> 2 Variable_1 += 1

NameError: name 'Variable_1' is not defined
  • Ebenso erlaubt aber besser lassen: Sonderzeichen

# DON'T DO IT!
übung = 1

Nutzung von Variablen in Strings#

Mit f'' können so genannte Format-Strings verwendet werden. In diesen Strings können innerhalb von geschweiften Klammern Ausdrücke stehen, die im String durch den ausgewerteten und zum String umgewandelten Ausdruck ersetzt werden. Optional kann in den geschweiften Klammern mit : noch ein Format für den Ausdruck eingefügt werden.

Beispiele:

world = 'Welt'
f'Hallo {world}'
'Hallo Welt'
a = 2.0
print(f'a = {a}')
print(f'2 * a = {2 * a}')
a = 2.0
2 * a = 4.0
b = 100.0
print(f'{a}\n{b}')
2.0
100.0
c = 1000
print(f'{a:8,.2f}\n{b:8,.2f}\n{c:8,.2f}')
    2.00
  100.00
1,000.00

7.5. Datenstrukturen#

Listen#

Listen können beliebige Werten in einer bestimmten Reihenfolge abspeichern. Die Werte in einer Liste können verschiedene Typen haben - üblich sind aber Listen von einem einzelnen Typ. Listen können verändert werden. Sie können direkt mit Hilfe von eckigen Klammern und durch Kommas separierte Werte im Code erstellt werden:

a = [1, 2, 3]
print(a)
[1, 2, 3]

Auf einzelne Werte wird mit [index] zugegriffen - sowohl lesend als auch schreibend. Es wird bei 0 angefangen zu zählen.

print(a[0])
a[0] = a[0] + 1
print(a[0])
1
2

Es kann auch vom Ende der Liste aus zugegriffen werden indem man einen negativen Index verwendet - hier fängt man bei -1 an zu zählen. Man kann auch auf einen Unterabschnitt der Liste zugriffen - auf ein sogenanntes slice. Dazu wird [start_index:end_index] verwendet. start_index ist inklusive mit Default-Wert 0; end_index ist exklusive mit Default-Wert entsprechend der Länge der Liste.

a[-1]
3
a[0:2] = [1,2]
a[0:3]
[1, 2, 3]
a[-2:]
[2, 3]

Mit + können Listen aneinander gehängt werden - das Ergebnis ist eine neue Liste. Mit der append()-Methode können neue Werte ans Ende der Liste angehängt werden. Die Funktion len() gibt die Länge der Liste aus. Sie funktioniert übrigens auch für Strings.

b = a + [4, 5, 6]
print(b)
[1, 2, 3, 4, 5, 6]
a.append(4)
print(a)
[1, 2, 3, 4]
len(a)
4
len("Hallo")
5

Tupel#

Tupel sind ebenso wie Listen ein Sequenz-Typ. Im Gegensatz zu Listen sind Tupel unveränderbar und werden häufig mit gemischten Datentypen verwendet, z.B. um zusammengehörende Daten zu strukturieren. Tupel werden als eine Reihe von kommaseparierten Werten angelegt. Klammern sind dabei optional.

# Create tuples with content Firstname, Lastname, Year of birth, Favorite foods
joe = ('Joe', 'Doe', 1984, ['Steak', 'Fish', 'Vegetables'])
jane = 'Jane', 'Doe', 1998, ['Fish', 'Eggs']

jane
('Jane', 'Doe', 1998, ['Fish', 'Eggs'])
first, last, yob, foods = joe

print(first)
print(foods)
Joe
['Steak', 'Fish', 'Vegetables']

Ranges#

Ranges sind ein weiterer Sequenz-Typ, der per Konstruktor angelegt wird und eine gleichförmige Integer-Reihe darstellen. Der Vorteil gegenüber einer Liste ist der geringe Speicherverbrauch, da die Elemente einer Range berechnet werden können und nicht vollständig im Hauptspeicher materialisiert werden muss. Mit list() kann aber genau diese Materialisierung in eine Liste vorgenommen werden. Es gibt zwei Varianten von range:

  • range(stop): Liefert die Integer-Reihe von 0 bis stop - 1

r = range(5)
r
range(0, 5)
list(r)
[0, 1, 2, 3, 4]
r[0]
0
r[-3:]
range(2, 5)
  • range(start, stop[, step]): Liefert die Integer-Reihe von start bis stop mit einer Schrittweite step

list(range(1,10,2))
[1, 3, 5, 7, 9]
list(range(0,51,5))
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
list(range(-1, -11, -1))
[-1, -2, -3, -4, -5, -6, -7, -8, -9, -10]

Dictionaries#

Ein Dictionary ist eine Datenstruktur, die key-value-Paare, so abspeichert, dass mit Hilfe des keys effizient auf den value zugegriffen werden kann. Diese Datenstruktur ist in anderen Programmiersprachen u.a. auch als Hashmap, Hashtable oder Assoziativspeicher bekannt. keys müssen einen unveränderbaren Typ haben, z.B. Strings oder Zahlen.

Ein leeres Dictionary wird mit {} angelegt, optional können in den geschweiften Klammern direkt key: value Paare per Komma separiert angelegt werden. Der Zugriff auf values erfolgt über den Key in geschweiften Klammern nach dem Dictionary.

d1 = {}
d1['Joe'] = 'Doe'
d1['Jane'] = 'Doe'
d1
{'Joe': 'Doe', 'Jane': 'Doe'}
d2 = {'Doe': ['Jane', 'Joe']}
d2['Doe'][0]
'Jane'
# Prüfen, ob ein key vorhanden ist:
'Jack' in d1
False
# Entfernen eines key-value Paars:
del d1['Joe']
d1
{'Jane': 'Doe'}

7.6. Kontrollstrukturen#

Bevor wir auf Kontrollstrukturen eingehen, müssen wir einen wichtigen Aspekt der Python-Syntax betrachten: Whitespaces sind wichtig. Statt Code-Blöcke mit { und } abzugrenzen, wie es in vielen Programmiersprachen üblich ist, werden Code-Blöcke in Python über die Einrückung bestimmt. Dabei ist es gängige Leerzeichen statt Tabs zu verweden. Ein Block wird eingeleitet mit einem : und enthält alle nachfolgenden Zeilen, die weiter eingerückt sind als die einleitende Zeile.

Ein Beispiel mit if:

if True:
    print('Hallo True')
    
if False:
    print('Hallo False')

print('Hallo zusammen')
Hallo True
Hallo zusammen

Blöcke können geschachtelt werden:

if 1 + 1 > 1:
    print('Die erste Bedingung ist wahr')
    if 1 != 2:
        if not False:
            print('Alle Bedingungen sind wahr')
Die erste Bedingung ist wahr
Alle Bedingungen sind wahr

Bedingungen#

Neben if und else können noch weitere Bedingungen mit elif eingefügt werden:

number = 10
if number < 10:
    print('Kleine Zahl')
elif number < 100:
    print('Mittlere Zahl')
else:
    print('Große Zahl')
Mittlere Zahl

while-Schleifen#

while-Schleifen bestehen aus dem Schlüsselwort while gefolgt von der Bedingung und danach ein Block, der so lange ausgeführt wird wie die Bedingung als Wahr ausgewertet wird.

i = 0
while i < 3:
    print(f'Durchgang mit i = {i}')
    i += 1
Durchgang mit i = 0
Durchgang mit i = 1
Durchgang mit i = 2

for-Schleifen#

for-Schleifen in Python folgen immer der Form for variable(n) in sequence - also dem was in anderen Programmiersprachen typischerweise als for-each-loop bekannt ist.

for i in ['Hallo', 'Welt']:
    print(i)
Hallo
Welt
for i in 'Hallo':
    print(i)
H
a
l
l
o

Die “klassische” for-Schleife, z.B. aus Java for(int i=0; i<10; i++) kann wie folgt ausgedrückt werden:

for i in range(10):
    print(i)
0
1
2
3
4
5
6
7
8
9

List Comprehensions#

Häufig dient eine Schleife nur dazu, aus einer Sequenz eine neue Liste zu erzeugen. Dafür gibt es in Python eine kompakte Schreibweise, die List Comprehension: [ausdruck for variable in sequenz]. Die beiden folgenden Zellen erzeugen dieselbe Liste:

quadrate = []
for i in range(5):
    quadrate.append(i ** 2)
quadrate
[0, 1, 4, 9, 16]
[i ** 2 for i in range(5)]
[0, 1, 4, 9, 16]

Optional kann am Ende eine Bedingung stehen, dann werden nur die Elemente übernommen, für die sie zutrifft:

[i for i in range(10) if i % 2 == 0]
[0, 2, 4, 6, 8]

Mit zip lassen sich mehrere Sequenzen parallel durchlaufen. In jedem Durchgang erhält man ein Tupel mit je einem Element aus jeder Sequenz, das wir wie bei den Tupeln oben direkt auf mehrere Variablen verteilen können:

staedte = ['Stockholm', 'Wien', 'Bilbao']
startjahre = [1919, 1978, 1887]
for stadt, jahr in zip(staedte, startjahre):
    print(f'{stadt}: {jahr}')
Stockholm: 1919
Wien: 1978
Bilbao: 1887

Beides lässt sich kombinieren. Das folgende Beispiel bildet aus einer Liste von Grenzen Beschriftungen für die Intervalle dazwischen, so wie wir es im Kapitel Feature Engineering brauchen werden:

grenzen = [0, 10, 100, 1000]
[f'{unten} - {oben}' for unten, oben in zip(grenzen[:-1], grenzen[1:])]
['0 - 10', '10 - 100', '100 - 1000']

Bei der Arbeit mit NumPy und pandas brauchen Sie List Comprehensions seltener, weil dort ganze Arrays und Spalten auf einmal verarbeitet werden. Für kleine Hilfslisten wie Spaltennamen oder Beschriftungen sind sie aber sehr praktisch.

7.7. Funktionen#

Funktionen werden mit def definiert. Es folgt der Funktionsname und dann in Klammern die Parameter. Der Code der Funktion folgt dann in einem Code-Block. Parameter können optional sein, wenn ein Default-Wert angegeben wird. Beispiel:

def begruessung(name, grusswort='Hallo'):
    print(f'{grusswort} {name}')

Aufgerufen werden Funktionen über ihren Namen gefolgt von den Parametern in Klammern:

begruessung('Joe')
Hallo Joe
begruessung('Jane', 'Hello')
Hello Jane

Bei Verwendung der Parameternamen, kann die Reihenfolge beim Funktionsaufruf geändert werden, z.B.:

begruessung(grusswort='Hello', name='World')
Hello World

Funktionen können auch anonym mit dem Schlüsselwort lambda erstellt werden und diese wiederum in Variablen gespeichert werden.

f = lambda a, b: a + b
g = lambda x: x * 2
f(1,2)
3
g(f(1,2))
6
list(map(lambda x: x * 2, [1, 2, 3]))
[2, 4, 6]
list(map(g, [1, 2, 3]))
[2, 4, 6]

7.8. Klassen, Objekte und Methoden#

Wir gehen nicht darauf ein, wie man in Python objektorientiert programmiert und eigene Klassen erstellt. Wir werden aber häufig Klassen und Objekte verwenden. Sowohl Klassen als auch Objekte (also Instanzen einer Klassen) können Attribute haben - das können entweder Variablen sein in denen Daten gespeichert werden oder Funktionen, die man im Kontext der Klasse oder des Objekts aufruft. Diese Funktionen entsprechen dann den bekannten Klassen- oder Instanzmethoden. Der Name des Attributes wird per Punkt an die Klasse oder das Objekt gehängt. Zu beachten im Vergleich z.B. zu Java:

  • In Python ist es üblich direkt Datenvariablen zu verwenden anstatt Getter und Setter zu implementieren

  • Methoden sind Attribute und daher wird ein Funktionsobjekt zurückgeliefert, wenn die Klammern (und ggfs. Parameter) nicht angegeben werden

a = "hallo"
# Ein String ist ein Objekt
# a.<TAB> liefert die Attribute, z.B. die capitalize-Methode
a.capitalize()
'Hallo'
# Ohne die Klammern bekommt man die Funktion geliefert
a.capitalize
<function str.capitalize()>

7.9. Bibliotheken#

Wir nutzen Python hauptsächlich als Schnittstelle, um auf mächtige Bibliotheken wie z.B. numpy zuzugreifen. Neben den bereits in der Standard-Library enthaltenen Bibliotheken können auf der Kommandozeile per pip3 install PAKETNAME oder in Jupyter-Notebook mit %pip install PAKETNAME weitere Pakete installiert werden. Mit from BIBNAME import ELEMENT können bestimmte Elemente aus einer Bibliothek in den lokalen Namespace importiert werden.

from datetime import  datetime

dt = datetime.now()
dt
datetime.datetime(2026, 9, 30, 20, 21, 3, 483709)
# Attribut von datetime.datetime-Objekten:
dt.year
2026
dt.strftime('%Y-%m-%d %H:%M:%S')
'2026-09-30 20:21:03'

Es ist auch möglich ganze Bibliotheken zu importieren mit import BIBNAME. Dann muss vor Elementen aus der Bibliothek immer BIBNAME. vorangestellt werden. Häufig wird dazu mit as ein kürzerer Alias vergeben, z.B.:

import numpy as np
np.array([1,2,3])
array([1, 2, 3])

7.10. Abschluss#

Dies war ein Kurzüberblick über die Grundlagen von Python, die es uns erlauben mächtige Bibliotheken zu nutzen. Weitere Aspekte werden wir bei Bedarf einführen, bzw. können eigenständig in der Python Dokumentation nachgeschlagen werden: https://docs.python.org/3/