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

1.1. Variablen und Datentypen

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

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 Funktionen die math-Bibliothek noch bereitstellt kann man

math.<TAB>

eingeben

Übungsaufgabe

Ermitteln Sie die Werte von \(\sin(x)\) für \(x\in \{0,\pi/2, \pi, 3\pi/2, 2\pi\}\).

In diesem Beispiel haben wir auch gesehen, wie zusätzliche Module eingebunden 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 *

einbinden und alle Funktionen und Variablen ohne Angabe des Bibliotheksnamens 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

1.1.2. Numerische Datentypen

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

Datentyp

Beschreibung

Beispiele

int

Ganze Zahlen

2, 3*8

float

Fließkommazahlen

2., 3/2, math.pi

bool

Bool’scher Wert

True, 1==0, 1<3

complex

Komplexe Zahlen

2+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

Für komplexe Zahlen sind entsprechende Rechenoperationen in der Bibliothek cmath definiert, die wir über

import cmath

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

cmath?

Hier ein kleines Beispiel:

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)

Übungsaufgabe

Berechne den Betrag und das Argument der Zahl 1+i.

Hinweis: Schaue dir zunächst an, welche Funktionen cmath bereitstellt.

1.1.3. Strings

Datentyp

Beschreibung

Beispiel

string

Eine 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 Apostrophen oder Gänsefüßchen 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__',
 '__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']

Die Methoden, welche mit 2 Unterstrichen beginnen sind private Methoden und sollten vom Programmierer nicht verwendet werden. Einige dieser Methoden dienen zur Überladung von Operatoren, beispielsweise realisiert die Methode __eq__ den Vergleichsoperator ==, oder __add__ den Additionsoperator +. Wir dieskutieren dies noch einmal genauer im Abschnitt Spezielle Methoden.

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

# Buchstaben zählen
print("Unser String enthält", a.count('e'), "mal den Buchstaben 'e'.")

# Nach Zeichenfolgen suchen
print("An Position", a.find("String"), "finden wir das Wort 'String'.")

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

a = a.replace("\n"," ") # Zeilenumbruch durch Leerzeichen ersetzen
a = a.replace(".", "")  # Satzzeichen entfernen
L = a.split(" ")        # String an Leerzeichen zerschneiden

print(L)
Unser String enthält 5 mal den Buchstaben 'e'.
An Position 12 finden wir das Wort 'String'.
I bims 1 String.
Ein sehr langer String.
Nun schon 3 Zeilen lang
['I', 'bims', '1', 'String', 'Ein', 'sehr', 'langer', 'String', 'Nun', 'schon', '3', 'Zeilen', 'lang']

Die Funktion string.split() erzeugt ein Objekt vom Typ list, welche wir im folgenden Abschnitt genauer diskutieren.

1.1.4. Containerklassen

Weitere wichtige Datentypen sind Listen und n-Tupel:

Datentyp

Beschreibung

Beispiele

list

Liste beliebig vieler Elemente beliebigen Typs

[1,2.2,'Hallo']

tuple

Ansammlung einer fixen Anzahl an Elementen

(1,"a")

Weitere Containerklassen sind set und dictionary, welche wir hier noch nicht behandeln möchten.

list ist ein Datentyp, welcher es erlaubt mehrere Objekte beliebigen Typs in einem Objekt zusammenzufassen. Ferner werden nützliche Funktionen bereitgestellt um auf die Liste zuzugreifen oder diese zu manipulieren. Mit list.<TAB> bekommen wir einen Überblick. Hier einige elementare Beispiele:

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                  # Konsolenausgabe
[1, 2, 3, 4, 5]

Interessant ist die Beobachtung, dass der Additionsoperator + auch für 2 Objekte vom Typ list definiert ist. Das Ergebnis ist offensichtlich die Konkatenation beider Listen.

Auch um Listen zu erstellen 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 lautet

for [elem] 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

Übungsaufgabe

Berechne die Summe der Zahlen 1 bis 10. Nutze entweder eine for-Schleife oder die Funktion sum(...).

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 gelb
Ich seh' etwas, was du nicht siehst, und das ist grün
Ich seh' etwas, was du nicht siehst, und das ist grün

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 \(r\) und das Argument \(\varphi\) von komplexen Zahlen \(z = a+i\,b = r\,e^{i\,\varphi}\):

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 erfolg wieder mit dem Operator [].

Noch eleganter ist allerdings folgende Schreibweise:

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

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

1.2. Klassen und Funktionen

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

  • Klassen

Jedes Objekt, auch Instanz genannt, gehört einer Klasse an, beispielsweise gehört 3.0 zur Klasse float, "Hallo" zur Klasse string und [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 unzählige weitere Klassen kennenlernen. Wichtig ist an dieser Stelle zu wissen, dass Klassen spezifische Attribute und Operationen für Instanzen dieser Klasse zusammenfassen. Beispielsweise speichert die Klasse complex den Real- und Imaginärteil einer komplexen Zahl, auf die wir mit

a.real
1.0

zugreifen. Ferner bietet die Klasse aber auch Operationen an um beispielsweise die konjugiert Komplexe zu berechnen (siehe Methoden).

  • Methoden

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

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

aufrufen. Ein Beispiel ist die Funktion conjugate(), welche für Objekte der Klasse complex definiert ist. 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. Die Dokumentation zu einer Methode erhalten wir mit

<instance>.<method>?
  • Freie Funktionen

Freie Funktionen hingegen 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