Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Erste Schritte

Wir wollen uns zunächst mit den Grundprinzipien der Programmiersprache Python vertraut machen. Insbesondere wollen wir lernen, welche Datentypen von Haus aus bereitgestellt werden, und wie wir mit diesen Arbeiten. Ferner wollen wir uns schon ein bisschen an die Syntax dieser Programmiersprache gewöhnen.

Variablen und Datentypen

Python als Taschenrechner verwenden

Python lässt sich wie ein Taschenrechner verwenden. Zwischenergebnisse können mit dem Zuweisungsoperator = ganz einfach in Variablen abgespeichert werden:

3+5
8
a = 3+5
b = a/2
b
4.0

Variablen müssen in Python nicht vorher deklariert werden. Der Datentyp wird automatisch anhand des zugewiesenen Wertes bestimmt.

Mit der type-Funktion lässt sich der Datentyp der Variable ermitteln:

print("a  ist ein", type(a))
print("2  ist ein", type(2))
print("2. ist ein", type(2.))
print("b  ist ein", type (b))
a  ist ein <class 'int'>
2  ist ein <class 'int'>
2. ist ein <class 'float'>
b  ist ein <class 'float'>

Weitere mathematische Funktionen sind im Modul math enthalten, welches zunächst in das Python-Skript eingebunden werden muss:

import math

print("Die Wurzel aus 9 ist", math.sqrt(9))
print("2 hoch 3 ist", 2**3)
print("Der natürliche Logarithmus aus 3 ist", math.log(3))
Die Wurzel aus 9 ist 3.0
2 hoch 3 ist 8
Der natürliche Logarithmus aus 3 ist 1.0986122886681098

Um zu erfahren welche Funktion das math-Modul noch bereitstellt, kann man im JupyterLab einfach

math.<TAB>

eingeben. Daraufhin erscheint eine Liste aller verfügbaren Funktionen und Konstanten des Moduls.

In diesem Beispiel haben wir auch gesehen, wie zusätzliche Module importiert und verwendet werden. Funktionen aus dem Modul math müssen hier mit math.sin(...) angesprochen werden. Alternativ kann man alle Funktionen einer Bibliothek mittels

from math import *

importieren und alle Funktionen und Variablen ohne Angabe des Modulnamens ansprechen.

Achtung: Hierbei können Namenskonflikte mit Funktionen und Variablen anderer Bibliotheken entstehen.

from math import *

print("Der Sinus von pi/2 ist", sin(pi/2))
Der Sinus von pi/2 ist 1.0

Numerische Datentypen

Wir haben im vorherigen Abschnitt bereits die type-Funktion kennengelernt und haben zwei verschiedene Datentypen bei unseren Berechnungen beobachtet. Die numerischen Datentypen sind in folgender Tabelle zusammengefasst:

DatentypBeschreibungBeispiele
intGanze Zahlen2, 3*8
floatFließkommazahlen2., 3/2, math.pi
boolBool’scher WertTrue, 1==0, 1<3
complexKomplexe Zahlen2+4j, cmath.sqrt(-9)

Boolsche Variablen nehmen lediglich die Werte wahr (True) oder falsch (False) an. Sie sind unter anderem das Ergebnis von Vergleichsoperationen:

a = 1 < 3
print("a ist eine Variable vom Typ", type(a), "und hat den Wert", a)
b = 1==0
print("b ist eine Variable vom Typ", type(b), "und hat den Wert", b)
a ist eine Variable vom Typ <class 'bool'> und hat den Wert True
b ist eine Variable vom Typ <class 'bool'> und hat den Wert False

Komplexe Zahlen sind in Python ein eingebauter Datentyp (complex). Die imaginäre Einheit wird dabei mit j statt mit i geschrieben. Für komplexe Zahlen sind entsprechende Rechenoperationen im Modul cmath definiert, das wir über

import cmath

einbinden können. Eine kurze Dokumentation zu einer Bibliothek bekommt man übrigens, wenn man

cmath?

in eine Code-Zelle eingibt.

Hier ein kleines Beispiel zu komplexen Zahlen:

import cmath

a = cmath.sqrt(-9)
print("Die Wurzel aus -9 ist", a)

b = 1+2j
c = a/b

print("Der Quotient aus a und b ist", c, "und ist wieder vom Typ", type(c))
print("Es gilt Re(c) =", c.real, 
      ", Im(c) =", c.imag, 
      "und die konjugiert Komplexe ist =", c.conjugate())
Die Wurzel aus -9 ist 3j
Der Quotient aus a und b ist (1.2+0.6j) und ist wieder vom Typ <class 'complex'>
Es gilt Re(c) = 1.2 , Im(c) = 0.6 und die konjugiert Komplexe ist = (1.2-0.6j)

Strings

DatentypBeschreibungBeispiel
stringEine beliebig lange Zeichenkette'Hello world', "ABCDE"

Ein Objekt vom Typ string ist eine Zeichenkette, wie wir sie bei den Konsolenausgaben vorher schon verwendet haben. Strings werden durch Apostrophe 'oder Anführungszeichen " begrenzt.

a = "Ich bin ein String."                # String erzeugen
a+= "\nEin sehr langer String."          # Einen weiteren String anhängen
a+= "\nNun schon "+str(3)+" Zeilen lang" # Integer in String verwandeln und anhängen

print(a)
Ich bin ein String.
Ein sehr langer String.
Nun schon 3 Zeilen lang

Das Sonderzeichen '\n' steht dabei für einen Zeilenumbruch. Um Objekte anderer Typen in einen string umzuwandeln, nutzen wir die Funktion str(). Der Additionsoperator + verknüpft 2 Strings miteinander und der Operator += hängt einen String an einen anderen an.

Geben wir a.<TAB> ein, bekommen wir wieder eine Liste mit nützlichen Funktionen, die wir auf Strings anwenden können. Alternativ lassen sich alle für Strings definierten Methoden wie folgt auflisten:

dir(a)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

Diese Liste enthält die Namen aller Methoden, die wir auf das Objekt a anwenden können. Eine Methode ist im Allgemeinen eine Funktionen, die auf Objekte eines bestimmten Datentyps (in unserem Beispiel string) angewendet werden kann. Der Aufruf einer Methode sieht folgendermaßen aus:

<result> = <object>.<method>(<param1>, <param2>, ...)
  • <object> ist der Name eines Python-Objekts (hier a, vom Typ string).

  • <method> ist der Name einer Methode aus der oben erzeugten Liste.

  • <result> ist das Objekt, das von der Methode zurückgegeben wird.

Es gibt allerdings auch Methoden, die nichts zurückgeben. In diesem Fall entfällt der Teil <result> =.

Testen wir dies mit der Methode replace, welche - wie der Name bereits vermuten lässt - bestimmte Zeichen(ketten) durch andere ersetzt. Die zentrale Frage lautet:

Welche Parameter muss ich der Methode übergeben und was gibt diese Methode zurück?

Dabei sei angemerkt: Ein guter Programmierer ist nicht derjenige, der sich Methoden und Parameter aller Datentypen auswendig merkt. Viel wichtiger ist es, Code-Dokumentationen lesen zu können.

Beispiel: Google nach python string replace und öffne den ersten Treffer: https://www.w3schools.com/python/ref_string_replace.asp. Diese Dokumentation enthält alles, was wir über diese Methode wissen müssen:

  • Zwei Parameter werden benötigt: ** oldvalue - der Teil des Strings, der ersetzt werden soll ** newvalue - die neue Zeichenkette, die anstelle von oldvalue eingefügt wird

  • Ein optionaler Parameter count legt fest, wie viele Vorkommen ersetzt werden sollen. Standardmäßig werden alle ersetzt.

  • Die Methode gibt einen neuen String zurück, der die Änderungen enthält.

Alternativ kann man die im JupyterLab eingebaute Dokumentation verwenden:

a.replace?

Das liefert z.B.:

Signature: a.replace(old, new, count=-1, /)
Docstring:
Return a copy with all occurrences of substring old replaced by new.

  count
    Maximum number of occurrences to replace.
    -1 (the default value) means replace all occurrences.

If the optional argument count is given, only the first count occurrences are
replaced.
Type:      builtin_function_or_method

Die Anwendung der replace-Methode für Strings sieht beispielsweise wie folgt aus:

# String definieren
a = "Ich bin ein String"

# Bestimmte Zeichenfolgen ersetzen
a = a.replace("Ich", "I")
a = a.replace("bin", "bims")
a = a.replace("ein", "1")

# Konsolenausgabe
print(a)
I bims 1 String

Wenn wir uns nochmals die Liste aller Methoden für Strings von oben anschauen, fällt auf, dass einige Methoden mit zwei Unterstrichen beginnen. Dies sind bewusst versteckte Methoden und sollten in der Regel nicht direkt verwendet werden.

Einige dieser Methoden dienen zur Überladung von Operatoren, z.B.:

  • __eq__ → realisiert den Vergleichsoperator ==

  • __add__ → realisiert den Additionsoperator +

Wir diskutieren dies noch einmal genauer im Abschnitt Spezielle Methoden.

In folgendem Beispiel wenden wir einige der für Strings definierten Methoden an:

# Verknüpfungsoperator += (ruft intern __add__ auf)
a = "Ich bin ein String,"
a+= " der schon recht lang ist"
print(a)

# Vergleichsoperator == (ruft intern __eq__ auf)
b = "abc"
v = (b == "abc") 
print("Die Aussage 'b ist gleich abc' ist", v)
Ich bin ein String, der schon recht lang ist
Die Aussage 'b ist gleich abc' ist True

Die Methode string.split() erzeugt ein Objekt vom Typ list, welchen wir im folgenden Abschnitt genauer diskutieren werden.

Containerklassen

Weitere wichtige Datentypen sind Listen und n-Tupel:

DatentypBeschreibungBeispiele
listListe beliebig vieler Elemente beliebigen Typs[1,2.2,'Hallo']
tupleAnsammlung einer festen Anzahl von Elementen(1,"a")
setMenge von einzigartigen Elementen{1, 2, 3}
dictSchlüssel-Wert-Paare{'Name': 'Max', 'Alter': 25}

Listen

Wir schauen uns zunächst Listen genauer an.

list ist ein Datentyp, der es erlaubt, mehrere Objekte beliebigen Typs in einem einzigen Objekt zusammenzufassen. Außerdem werden zahlreiche nützliche Methoden bereitgestellt, um auf die Elemente der Liste zuzugreifen oder die Liste zu verändern.

dir(list)
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

Wir sehen, dass der Datentyp list Methoden wie append, clear, copy usw. bereitstellt.

Außerdem sehen wir, dass auch ein Additionsoperator (über __add__), ein Vergleichsoperator (über __le__) und ein Multiplikationsoperator (über __mul__) definiert sind.

Probieren wir einige dieser Methoden aus:

L = [1,3,5]        # Liste erzeugen              [1,3,5]
L.append(2)        # Element anhängen            [1,3,5,2]
L = L + [4,6]      # Eine weitere Liste anhängen [1,3,5,2,4,6] 
L.sort()           # Liste sortieren             [1,2,3,4,5,6]
L.pop()            # Letztes Element entfernen   [1,2,3,4,5]
L = 2 * L          # Liste verdoppeln            [1,2,3,4,5,1,2,3,4,5]
L                  # Konsolenausgabe
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

Auch zum Erzeugen von Listen gibt es mehrere Möglichkeiten. Nützlich ist hierbei die Klasse range (siehe range? für eine genaue Beschreibung). Einige Beispiele:

L1 = list(range(10)) # Äquivalent zu L1 = [0,1,2,...,9]
print("L1 =", L1, ": enthält", len(L1), "Elemente")
L1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] : enthält 10 Elemente
L2 = list(range(1,11,2)) # Ungerade Zahlen von 1 bis 10
print("L2 =", L2, ": enthält", len(L2), "Elemente")
L2 = [1, 3, 5, 7, 9] : enthält 5 Elemente

Mit einer for-Schleife können wir über eine Liste iterieren und auf einzelne Elemente zugreifen. Die Syntax einer solchen Schleife sieht wie folgt aus:

for [element] in [liste]:
    [do something]

Ein einfaches Beispiel:

for a in L:
    print("Die Liste enthält", a)
Die Liste enthält 1
Die Liste enthält 2
Die Liste enthält 3
Die Liste enthält 4
Die Liste enthält 5
Die Liste enthält 1
Die Liste enthält 2
Die Liste enthält 3
Die Liste enthält 4
Die Liste enthält 5

Um ein einzelnes Element einer Liste zu lesen oder zu schreiben nutzt man den Zugriffsoperator []. Beachte, dass das erste Element den Index 0 besitzt, das zweite den Index 1, etc..

import random # Zufallszahlengenerator

farben = ['rot', 'blau', 'grün', 'schwarz', 'gelb']

for i in range(3):
    index = random.randint(0, len(farben)-1) # Erzeuge Zufallszahl zwischen 0 und 4
    farbe = farben[index]                    # Wähle die entsprechende Farbe
    print("Ich seh' etwas, was du nicht siehst, und das ist", farbe)
Ich seh' etwas, was du nicht siehst, und das ist rot
Ich seh' etwas, was du nicht siehst, und das ist gelb
Ich seh' etwas, was du nicht siehst, und das ist blau

Tupel

Zuletzt untersuchen wir die Klasse tuple. Diesen Container verwendet man für geordnete Listen einer festen Größe. Diese finden beispielsweise Einsatz bei Funktionen, welche 2 oder mehrere Werte zurückgeben. Diese Werte werden dann als n-Tupel zurückgegeben. Ein Beispiel ist der Betrag rr und das Argument φ\varphi von komplexen Zahlen z=a+ib=reiφz = a+i\,b = r\,e^{i\,\varphi}:

import cmath

a = 1+3j
res = cmath.polar(a)
print("Der Rückgabewert", res, "der Funktion 'cmath.polar' ist vom Typ", type(res))
Der Rückgabewert (3.1622776601683795, 1.2490457723982544) der Funktion 'cmath.polar' ist vom Typ <class 'tuple'>
print("Betrag   :", res[0])
print("Argument :", res[1])
Betrag   : 3.1622776601683795
Argument : 1.2490457723982544

Der Zugriff auf ein Element des Tupels erfolgt wieder mit dem Operator [].

Noch eleganter ist allerdings Tuple-Unpacking:

(a_abs, a_arg) = cmath.polar(a)

print("Betrag   :", a_abs)
print("Argument :", a_arg)
Betrag   : 3.1622776601683795
Argument : 1.2490457723982544

Klassen und Funktionen

In den letzten Abschnitten haben wir schon einige wichtige Konzepte der Programmiersprache Python kennengelernt. Diese wollen wir hier nochmal zusammenfassen.

  • Variablen

Hinter jeder Variablen verbirgt sich ein Objekt, auch Instanz genannt. Jede Instanz, gehört einer Klasse an, beispielsweise gehört

  • 3.0 zur Klasse float

  • "Hallo" zur Klasse string

  • [1,2,3] zur Klasse list

Zu welcher Klasse eine Instanz gehört erfahren wir dabei mit der Funktion type(...).

Wir werden im Laufe dieser Vorlesung noch viele weitere Klassen kennenlernen und sogar eigene erstellen. Wichtig ist an dieser Stelle zu wissen, dass Klassen spezifische Attribute und Operationen für Instanzen dieser Klasse zusammenfassen.

Beispiel: Die Klasse complex speichert den Real- und Imaginärteil einer komplexen Zahl. Darauf können wir zugreifen mit:

a.real
1.0
a.imag
3.0
  • Methoden

Methoden sind Funktionen, welche an Instanzen einer Klasse gekoppelt sind. Diese lassen sich mit

<result> = <instance>.<method>(<param1>, <param2> [...])

aufrufen. Methoden, die keine Eingabeparameter benötigen, werden dennoch mit leeren Klammern () aufgerufen.

Die Dokumentation zu einer Methode erhalten wir mit

<instance>.<method>?

Um zu erfahren welche Methoden eine Klasse anbietet, erzeugen wir eine Instanz a dieser Klasse und tippen a.<TAB> ins Notebook ein, oder führen die Funktion dir(a) aus.

Beispiel: Die Klasse complex stellt die Funktion conjugate() bereit und kann wie folgt aufgerufen werden:

b = a.conjugate()
print("Die konjugiert komplexe Zahl von", a, "ist", b)
Die konjugiert komplexe Zahl von (1+3j) ist (1-3j)
  • Freie Funktionen

Freie Funktionen sind nicht an eine Klasse gekoppelt, sondern lassen sich ohne Angabe der Instanz aufrufen.

Ein Beispiel ist die Funktion sum(...). Oft lassen sich diese Funktionen auf Objekte von unterschiedlichen Klassen anwenden. So funktioniert die Funktion sum(...) für Listen

sum([1,2,3])
6

als auch für Tupel

sum((1,2,3))
6

Für Strings hingegen ist die Funktion sum nicht anwendbar und gibt einen Fehler aus:

For strings, however, the function sum is not applicable and produces an error:

sum("Teststring")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[26], line 1
----> 1 sum("Teststring")

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