Datenstrukturen_Grundlagen¶
(c) 2026 Technische Hochschule Augsburg - Fakultät für Informatik - Prof.Dr.Nik Klever - Impressum
Datenstrukturen Grundlagen¶
Listen und Dictionaries¶
Listen und Tupel¶
Mit Listen können beliebige Objekte zusammengefasst werden. Diese Objekte können dann individuell angesprochen, verändert, gelöscht oder es können neue hinzugefügt werden. Eine Liste kann auch mit der Klasse list erzeugt werden.
Im Gegensatz dazu ist das Tupel (,) (tuple) eine unveränderliche Liste.
Hinweis:
Für die Indizierung von Listen gibt es entweder die Möglichkeit die range-Funktion zu verwenden oder die Methode index aus der Klasse Sequence-Types.
a = ['eins','zwei','drei','vier','fünf']
print(a[0])
print(a[4])
b = ['drei','vier','fünf','sechs','sieben','acht']
a += ['sechs','sieben']
a
eins fünf
['eins', 'zwei', 'drei', 'vier', 'fünf', 'sechs', 'sieben']
Kopien von Listen¶
a = [1,2,3,4]
b = a
b[0] = 4
print(a)
print(b is a)
[4, 2, 3, 4] True
b = a[:]
print(b is a)
b[0] = 1
print(a)
print(b)
False [4, 2, 3, 4] [1, 2, 3, 4]
Strings sind unveränderlich¶
wort = "Python"
wort[0] = "C"
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In [5], line 2 1 wort = "Python" ----> 2 wort[0] = "C" TypeError: 'str' object does not support item assignment
wort = "C"+wort[1:]
print(wort)
Cython
Mengen¶
Sowohl set als auch frozenset erlauben Mengenoperationen auf ihren Objekten.
a = [1,2,3,4]
b = [3,4,5,6,7,8]
c = set(a)
d = set(b)
print(c&d)
print(c|d)
print(c-d)
print(d-c)
{3, 4}
{1, 2, 3, 4, 5, 6, 7, 8}
{1, 2}
{8, 5, 6, 7}
Dictionaries¶
Mit Dictionaries (Wörterbuch, Hashmap) können ebenfalls beliebige Objekte als Schlüssel-Wert-Paare zusammengefasst werden. Die Objekte eines Dictionaries können über ihre Schlüssel ebenfalls individuell angesprochen, verändert, gelöscht oder es können neue hinzugefügt werden. Ein Dictionary kann auch mit der Klasse dict erzeugt werden.
a = dict(eins=1,zwei=2,drei=3)
a
{'eins': 1, 'zwei': 2, 'drei': 3}
print(a)
{'eins': 1, 'zwei': 2, 'drei': 3}
In dem folgenden Beispiel ist die Erzeugung der Dictionaries a,b,c,d,e alternative Methoden. Dabei ist die Methode b die allgemeinste und diejenige die auch als Ausgabe für Dictionaries verwendet wird
a = dict(eins=1,zwei=2,drei=3)
b = {'vier':4,'fünf':5,'sechs':6}
c = dict(zip(['sieben', 'acht', 'neun'], [7, 8, 9]))
d = dict([('zehn', 10), ('elf', 11)])
e = dict({'zwölf': 12, 'dreizehn': 13, 'vierzehn': 14})
a.update(b)
a.update(c)
a.update(d)
a.update(e)
print(a)
print(sorted(a.items(), key=lambda t: t[0]))
{'eins': 1, 'zwei': 2, 'drei': 3, 'vier': 4, 'fünf': 5, 'sechs': 6, 'sieben': 7, 'acht': 8, 'neun': 9, 'zehn': 10, 'elf': 11, 'zwölf': 12, 'dreizehn': 13, 'vierzehn': 14}
[('acht', 8), ('drei', 3), ('dreizehn', 13), ('eins', 1), ('elf', 11), ('fünf', 5), ('neun', 9), ('sechs', 6), ('sieben', 7), ('vier', 4), ('vierzehn', 14), ('zehn', 10), ('zwei', 2), ('zwölf', 12)]
from collections import OrderedDict
a = OrderedDict(eins=1)
a.update(zwei=2)
a.update(drei=3)
b = OrderedDict({'vier':4})
b.update({'fünf':5})
b.update({'sechs':6})
a.update(b)
print(a)
OrderedDict([('eins', 1), ('zwei', 2), ('drei', 3), ('vier', 4), ('fünf', 5), ('sechs', 6)])
Aktives Plenum¶
Erstellen sie ein Adressbuch ihrer Kontakte, denken sie dabei immer an die Kontakte-App in ihrem Smartphone, wie wird das Adressbuch dort umgesetzt.
- Überlegen sie sich zuerst was zu einem Kontakt dazugehört
- überlegen sie sich weiterhin, wie ihre Kontakte aufgelistet werden
Aus beiden Überlegungen sollten sie jetzt mit den vorhandenen Mitteln ein Adressbuch erstellen können.
kontakt = [dict(Vorname='Klaus',Nachname='Müller',Telefon='0171/1234567',EMail='klaus.mueller@gmx.de'),
dict(Vorname='Wolfgang',Nachname='Haberkorn',Telefon='0172/5678967',EMail='w.haberkorn@mail.de'),
dict(Vorname='Jürgen',Nachname='Petermann',Telefon='0153/112334555678967',EMail='juergen.petermann@telekom.de')
]
print(kontakt)
[{'Vorname': 'Klaus', 'Nachname': 'Müller', 'Telefon': '0171/1234567', 'EMail': 'klaus.mueller@gmx.de'}, {'Vorname': 'Wolfgang', 'Nachname': 'Haberkorn', 'Telefon': '0172/5678967', 'EMail': 'w.haberkorn@mail.de'}, {'Vorname': 'Jürgen', 'Nachname': 'Petermann', 'Telefon': '0153/112334555678967', 'EMail': 'juergen.petermann@telekom.de'}]
Klasse¶
Klassen-Attribute¶
class Ort(object):
Ost = 0.0 # Längengrad
Nord = 0.0 # Breitengrad
Hoehe = 0.0 # Höhenangabe
Beschreibung = "" # Ortsbeschreibung
Klassen-Instanz¶
ort = Ort()
ort.Ost
0.0
ort.Nord = 48.355
ort.Nord
48.355
Klassen-Methoden¶
- alle Klassen-Methoden haben als ersten Parameter die Instanzvariable self
- die Konstruktor-Methode einer Klasse muss __init__ heissen
class Ort():
Hoehe = 0.0
def __init__(self, nord, ost, hoehe=0):
self.Ost = ost
self.Nord = nord
if hoehe: self.Hoehe = hoehe
def getKoord(self):
return (self.Nord,self.Ost)
def setKoord(self,nord,ost):
self.Ost = ost
self.Nord = nord
Klassen-Instanz¶
ort = Ort()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In [17], line 1 ----> 1 ort = Ort() TypeError: __init__() missing 2 required positional arguments: 'nord' and 'ost'
ort = Ort(48.358163,10.906377)
ort.getKoord()
(48.358163, 10.906377)
ort.Hoehe
0.0
Aktives Plenum¶
Erstellen sie jetzt nochmal ein Adressbuch ihrer Freunde mit ihren Kontakte, denken sie dabei wieder an die Kontakte-App in ihrem Smartphone, wie wird das Adressbuch dort umgesetzt.
- Überlegen sie sich zuerst was zu einem Freund dazugehört
- und erweitern sie daher die oben aufgezählten Eigenschaften eines Kontaktes
- Erstellen sie jetzt aber die Freunde als Instanz einer Klasse, die allgemeiner "Person" benamt sein sollte
- Überlegen sie, ob sie eine Trennung der Eingabe der Eigenschaften der Person und der des Kontaktes durchführen
- Das Adressbuch sollte nun ebenfalls aus einer Liste bestehen
Vergleichen sie nun die beiden Datenmodelle und überlegen sich die Vorteile und Nachteile beider Modelle.
class Person():
def __init__(self,vorname,nachname,geburtsdatum,geschlecht='w'):
self.Vorname = vorname
self.Nachname = nachname
self.Geburtsdatum = geburtsdatum
self.Geschlecht = geschlecht
self.Telefon = []
self.EMail = []
def Kontakt(self,telefon=None,email=None):
if telefon: self.Telefon.append(telefon)
if email: self.EMail.append(email)
adressbuch = [Person('Axel','Müller','1.10.1995','m'),
Person('Sigi','Meyer','3.5.1993')]
adressbuch[0].Kontakt('0171/1234567')
adressbuch[0].Kontakt('089/35639866')
adressbuch[0].Telefon
['0171/1234567', '089/35639866']
import datetime
class Person():
def __init__(self,vorname,nachname,geburtsdatum,geschlecht='w'):
self.Vorname = vorname
self.Nachname = nachname
self.Geburtsdatum = geburtsdatum
self.Geschlecht = geschlecht
self.Telefon = []
self.EMail = []
def Kontakt(self,telefon=None,email=None):
if telefon: self.Telefon.append(telefon)
if email: self.EMail.append(email)
def Alter(self):
return datetime.date.today().year-self.Geburtsdatum.year
person = Person('Axel','Müller',datetime.date(1995,10,1),'m')
person.Kontakt('0171/1234567')
person.Kontakt('089/35639866')
person.Telefon
person.Alter()
27
Excel¶
%%writefile personendaten.csv
Vorname;Nachname;Geburtsdatum;Geschlecht
Anne;Müller;10.10.1980;w
Tobi;Franz;03.05.1982;m
Axel;Müller;1.10.1995;m
Siglinde;Meyer;3.5.1993;w
Writing personendaten.csv
import datetime
class Person():
def __init__(self,vorname,nachname,geburtsdatum,geschlecht='w'):
self.Vorname = vorname
self.Nachname = nachname
if isinstance(geburtsdatum,str):
tag, monat, jahr = geburtsdatum.split('.')
self.Geburtsdatum = datetime.date(int(jahr),int(monat),int(tag))
elif isinstance(geburtsdatum,datetime.date):
self.Geburtsdatum = geburtsdatum
else:
raise "Geburtsdatum falsch eingegeben"
self.Geschlecht = geschlecht
self.Telefon = []
self.EMail = []
def Kontakt(self,telefon=None,email=None):
if telefon: self.Telefon.append(telefon)
if email: self.EMail.append(email)
def Alter(self):
return datetime.date.today().year-self.Geburtsdatum.year
f = open('personendaten.csv','r')
gesamterInhalt = f.read()
f.close()
zeilen = gesamterInhalt.split('\n')
spaltendefinition = zeilen[0].split(';')
print(spaltendefinition)
adressbuch = []
for zeile in zeilen[1:-1]:
spalten = zeile.split(';')
person = Person(spalten[spaltendefinition.index('Vorname')],
spalten[spaltendefinition.index('Nachname')],
spalten[spaltendefinition.index('Geburtsdatum')],
spalten[spaltendefinition.index('Geschlecht')])
adressbuch.append(person)
print([p.Nachname for p in adressbuch])
['Vorname', 'Nachname', 'Geburtsdatum', 'Geschlecht'] ['Müller', 'Franz', 'Müller', 'Meyer']
HTML in jupyter¶
%%HTML
<html>
<head>
</head>
<body>
<h1>
<b>
<i>
Überschrift
</i>
</b>
</h1>
<p>
<a href="url">Link</a>
<hr/>
</p>
</body>
</html>
Module¶
Module in Python sind analog wie die Packages in Java zur Strukturierung vorgesehen
Standardmodule¶
Übersicht über alle Standardmodule¶
Modul sys¶
- für die Übergabe von Parametern aus dem python-(oder ipython-)Shell-Aufruf
import sys
print(sys.argv)
['/home/nik/miniconda3/envs/jupyter/lib/python3.9/site-packages/ipykernel_launcher.py', '-f', '/home/nik/.local/share/jupyter/runtime/kernel-8f9315d6-b3eb-4fc0-91ce-2131898067c0.json']
z.B. stehen durch den Shell-Aufruf
$> python test.py parameter1 8.9 "Dies ist ein Text" parameter2
die folgenden Werte in sys.argv:
['test.py', 'parameter1', '8.9', 'Dies ist ein Text', 'parameter2']
Typisches Python Problem mit Übergabeparametern (sys.argv)¶
@Desktop:~/$ python client.py
Traceback (most recent call last):
File "client.py", line 8, in
text = sys.argv[1]
IndexError: list index out of range
@Desktop:~/$
Interpretation dieser Fehlermeldung¶
- der Fehler taucht in der Datei client.py in der Zeile 8 auf
- in dieser Zeile ist der folgende Code fehlerhaft text = sys.argv[1]
- Es ist ein IndexError mit dem genauen Hinweis: list index out of range, d.h. das Programm kann auf den angegebenen Index dieser Liste nicht zugreifen, dieser Index existiert nicht.
Was bedeutet dies nun¶
Die Funktion sys.argv übergibt die Parameter aus der Kommandozeile. Nähere Informationen hierzu finden Sie an der entsprechende Stelle im Modul sys in der Python Dokumentation. Wenn nun der angegebene Index sys.argv[1] nicht existiert, heisst dies, dass der entsprechende Parameter in der Kommandozeile nicht angegeben ist - wie ja auch in der ersten Zeile zu erkennen ist (es wird kein Parameter hinter client.py übergeben).
Richtig wäre also hier den Aufruf:
@Desktop:~/$ python client.py irgendeine_text_datei
Typisches Beispiel um alle Pfade, die für den import von Modulen durchsucht werden, aufzulisten¶
import sys
print(sys.path)
['/home/nik/Server/Notebooks/OWL/AIM@LMU', '/home/nik/miniconda3/envs/jupyter/lib/python39.zip', '/home/nik/miniconda3/envs/jupyter/lib/python3.9', '/home/nik/miniconda3/envs/jupyter/lib/python3.9/lib-dynload', '', '/home/nik/miniconda3/envs/jupyter/lib/python3.9/site-packages']
Eigene Module¶
Datei uebergabe.py¶
%%writefile uebergabe.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
print("Wir sind jetzt in uebergabe.py")
try:
print("__file__:",__file__)
except:
print('__file__ does not exist')
print("uebergabe.py: __name__:",__name__)
if __name__ == '__main__':
print("jetzt habe ich uebergabe.py direkt aufgerufen")
else:
print("Wir verlassen jetzt uebergabe.py")
Writing uebergabe.py
!python uebergabe.py
Wir sind jetzt in uebergabe.py
('__file__:', 'uebergabe.py')
('uebergabe.py: __name__:', '__main__')
jetzt habe ich uebergabe.py direkt aufgerufen
Datei test.py¶
Damit die Datei uebergabe.py auch importiert wird, muss sie im selben Ordner stehen, in dem auch das jupyter notebook aufgerufen wurde.
%%writefile test.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
print("Wir sind jetzt in test.py")
import uebergabe
print("Nach dem import von uebergabe")
print("test.py: __name__:",__name__)
Writing test.py
!python test.py
Wir sind jetzt in test.py
Wir sind jetzt in uebergabe.py
('__file__:', '/home/nik/Server/Notebooks/OWL/AIM@LMU/uebergabe.py')
('uebergabe.py: __name__:', 'uebergabe')
Wir verlassen jetzt uebergabe.py
Nach dem import von uebergabe
('test.py: __name__:', '__main__')
Beispiel eines eigenen Moduls rechne.py¶
mit der Intention, den direkten Aufruf der Datei zum Testen zu verwenden:
Datei rechne.py¶
%%writefile rechne.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
def addiere(parameter1, parameter2):
return parameter1+parameter2
def multipliziere(parameter1, parameter2):
return parameter1*parameter2
if __name__ == '__main__':
print("Test addiere:", addiere(2,6))
print("Test multipliziere:", multipliziere(3,2))
Writing rechne.py
!python rechne.py
('Test addiere:', 8)
('Test multipliziere:', 6)
Datei verwende_rechne.py¶
%%writefile verwende_rechne.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
import rechne
print("Addition 4+5=",rechne.addiere(4,5))
Writing verwende_rechne.py
!python verwende_rechne.py
('Addition 4+5=', 9)
Hier gilt natürlich ebenfalls, dass die Datei rechne.py auch nur dann importiert wird, wenn sie im selben Ordner steht, in dem auch das ipython notebook aufgerufen wurde.
import in jupyter¶
Der Aufruf von import wird in einer Datei immer nur ein einziges Mal verwendet. Bei einem zweiten Aufruf wird dieser Aufruf nicht mehr ausgeführt. Dies gilt auch für Jupyter. D.h. wird ein import in einer Zelle ausgeführt, wird er nur das erste Mal nach dem Aufruf von Jupyter aufgerufen wird, bei jeder weiteren Ausführung dieses Codeblocks wird der import nicht mehr ausgeführt.
Add-On¶
JavaScript Object Notation (JSON) Data Interchange Format¶
Ursprünglich von Douglas Crockford entwickeltes JavaScript kompatibles Format zur Übertragung von JavaScript Objekten vom Server zum Client (RFC 4627, 2006), weiterentwickelt und sowohl als ECMA-Standard 404 wie auch als RFC 7159 veröffentlicht.
Eine sehr schöne deutsche Zusammenfassung ist auf der json.org Webseite einschliesslich einer Auflistung von unterstützten Programmiersprachen zu finden.
Prinzipiell baut JSON auf den eben beschriebenen zwei Objektstrukturen Liste und Dictionary auf, wird dort aber Array und Object benannt.
In Python ist die Bibliothek json in der Standardbibliothek enthalten und enthält im wesentlichen die zwei Methoden dump und load für File-Objekte bzw. dumps und loads für String-Objekte.
Aktives Plenum¶
Suchen sie sich auf ihrem Verzeichnis eine IPython Notebook Datei (verwenden sie hierzu glob.glob) und lesen sie diese Datei mit der obigen Funktion leseDatei ein. Importieren sie zudem die Bibliothek json sowie die Bibliothek pprint.
Erzeugen sie nun aus dem Ergebnis ihrer eingelesenen Datei ein verarbeitbares Objekt und geben dieses mit der Methode pprint aus der gleichnamigen Bibliothek aus. pprint erzeugt eine gut lesbare Struktur des entsprechenden Objekts.
Geben sie nun aus der ersten Zelle den Zellen-Typ an sowie den entsprechenden Inhalt der Zelle aus. In welchem Objekt steckt der Inhalt, wenn es eine Markdown-Zelle ist und in welchem, wenn es ein Code-Zelle ist ?
import glob
import json
import pprint
def leseDatei(dateiname):
try:
datei = open(dateiname,"r")
gesamterText = datei.read()
datei.close()
return gesamterText
except IOError:
print("Die Datei {} wurde nicht gefunden".format(dateiname))
return None
x=glob.glob('P*.ipynb')
if len(x)>0: rs = leseDatei(x[0])
else: rs = "{}"
ipynb = json.loads(rs)
#pprint.pprint(ipynb)
rs = ipynb['cells'][0]
print(rs['cell_type'])
print(rs['source'])
markdown ['# Beispiel Jupyter Notebook\n', '\n', '## Code Zellen']