.. include:: markup.rst
****************
Datenspeicherung
****************
Es gibt eine :mark:`Reihe von Möglichkeiten` wie man Daten speichern kann.
Welche Methode am besten ist, :mark:`hängt von Kriterien ab` wie:
* Datentyp
* Datenmenge
* Zugriffsgeschwindigkeit
* Erweiterbarkeit
* Implementierungsaufwand vs. Nutzen
Tabellenformate
===============
CSV / Text Format
-----------------
Ein sehr verbreitetes :mark:`Import- und Exportformat für Datenbanken` und
:mark:`Tabellenkalkulationen` ist das CSV-Format (Comma Separated Values).
CSV-Dateien sind Textdateien, die zeilenweise Datensätze enthalten welche
mit :mark:`Trennzeichen` (``,``, ``;``, ...) versehen sind z.B.: ::
Marke;Modell;Leistung
Porsche;911;350
Skoda;Octavia;140
Audi;Q3;110
Dabei ist die erste Zeile die :mark:`Datenbezeichnung`. Solche Daten können mit
unterschiedlichsten Softwareapplikationen erzeugt werden.
Die :mark:`einfachste Möglichkeit` aus Python Daten zu schreiben,
ist unter ":ref:`Daten in eine Datei schreiben`" erläutert d.h. mittels
``for`` und ``print`` Statement.
Eine solche Datei kann mit dem Python ``csv`` Modul eingelesen werden: ::
In [1]: import csv
In [2]: with open("daten.csv", "r") as csvfile:
...: reader = csv.reader(csvfile, delimiter=";")
...: for row in reader:
...: print(row)
...:
['Marke', 'Modell', 'Leistung']
['Porsche', '911', '350 ']
['Skoda', 'Octavia', '140 ']
['Audi', 'Q3', '110 ']
bzw. wieder in eine Datei geschrieben werden: ::
In [3]: with open("test_daten.csv", "w", newline='') as csvfile:
...: writer = csv.writer(csvfile, delimiter=';')
...: writer.writerow(['Marke', 'Modell', 'Leistung'])
...: daten = ( ['Porsche', '911', '350 '],
...: ['Skoda', 'Octavia', '140 '],
...: ['Audi', 'Q3', '110 '])
...: writer.writerows(daten)
Anmerkungen:
* Mit ``"wb"`` statt ``"w"`` kann man :mark:`Binärfiles` schreiben (mit ``"rb"`` wieder lesen).
* für korrekte Zeilenendungen auf unterschiedlichen Plattformen wird ``newline=''`` empfohlen. (siehe https://docs.python.org/3/library/csv.html#id3)
* Es können Files geschrieben werden, welche direkt von Microsoft :mark:`EXCEL gelesen werden` können (einfach anklicken im Explorer).
XLSX Format
-----------
Weit verbreitet ist das Microsoft :mark:`XLSX File Format`. Mit dem Modul ``openpyxl`` lassen sich diese Files direkt schreiben (siehe Beispiel ``daten_xlsx.py``).
.. literalinclude:: src/daten_xlsx.py
.. figure:: images/excel2.png
:scale: 70 %
:align: center
Das :mark:`Lesen` von XLSX ist wesentlich aufwendiger aufgrund von "Merged Cells", Formeln, etc. und wird hier nicht näher behandelt. Ein einfaches Beispiel dazu (siehe ``daten_xlsx2.py``):
.. literalinclude:: src/daten_xlsx2.py
Python Pandas
-------------
Hat man :mark:`große numerische Datenmengen` welche manipuliert und analysiert werden, ist Python `Pandas
`_ die richtige Bibliothek. Vereinfacht gesprochen steht dahinter ein sehr effizientes Tabellenformat mit vielen Analyse- und Visualisierungfunktionen.
.. figure:: images/pandas.png
:scale: 50 %
:align: center
Beispielsweise können sehr einfach ``xlsx`` Daten gelesen und verarbeitet werden (Fortsetzung des oberen Beispiels): ::
In [1]: import pandas as pd
In [2]: meineAutos = pd.read_excel('daten.xlsx', sheet_name='Meine Autos')
In [3]: print(meineAutos)
Marke Modell Leistung
0 Porsche 911 350
1 Skoda Octavia 140
2 Audi Q3 110
In [4]: print(meineAutos.values)
[['Porsche' '911' 350]
['Skoda' 'Octavia' 140]
['Audi' 'Q3' 110]]
XML Dateien
===========
Das :mark:`CSV Format` ist
* einfach lesbar, aber
* nicht einfach erweiterbar und wartbar.
Alternative: Das :mark:`XML Format` (Extensible Markup Language).
Dieses Format ist :
* eine hierarchisch aufgebaute Datenstruktur (erweiterbar), welche
* in einem lesbaren Textformat verfasst ist.
Für das obige Beispiel würde ein XML File so aussehen (``daten.xml``): ::
Porsche
911
350
Skoda
Octavia
140
Audi
Q3
110
Man bezeichnet diese Datenstruktur als :mark:`Document Object Model` (DOM).
Die Abbildung `XML DOM Baum`_ zeigt die grafische Darstellung.
.. _`XML DOM Baum`:
.. figure:: images/dom.png
:scale: 80 %
:align: center
Beispiel eines XML DOM Baumes
Erklärung:
* Der Baum besteht aus :mark:`Elementen`.
* Übergeordnete heißen :mark:`Parents`, untergeordnete :mark:`Childs` und
jene auf der gleichen Ebene :mark:`Siblings`.
* Auf der untersten Ebene werden die Daten als :mark:`Text` gespeichert.
Das Lesen/Schreiben kann mit folgenden Python Modulen implementiert werden:
* ``xml.dom.minidom`` Document Object Model, kurz DOM (liest alles in Speicher)
* ``xml.sax`` Simple API for XML, kurz SAX (liest fortlaufend in Speicher)
* ``xml.etree.ElementTree``, einfacher als die beiden anderen, i.A.
ausreichend.
Hier ein Beispiel (``daten_xml_elementtree.py``) mit ``xml.etree.ElementTree``:
.. literalinclude:: src/daten_xml_elementtree.py
Ausgabe: ::
Porsche 911 350
Skoda Octavia 140
Audi Q3 110
Für Genaueres zu diesem Thema wird auf die Literatur verwiesen.
Datenbanken
===========
:mark:`Große bzw. komplexe Datenmengen` benötigen entsprechende
:mark:`Verwaltungsprogramme`. Obige Konzepte sind dafür nur
bedingt geeignet. Man verwendet daher :mark:`Datenbanken`.
Bei einer Datenbank wird zwischen dem Programm und
dem Massenspeicher (Festplatte, ..) ein Zwischenlayer
(:mark:`Datenbanksystem`) eingeführt
(siehe Abbildung `Datenbankschnittstelle`_).
.. _`Datenbankschnittstelle`:
.. figure:: images/datenbank.png
:scale: 80 %
:align: center
Datenbankschnittstelle
Allgemeines:
* Das Datenbanksystem nimmt dabei Abfragen, sogenannte :mark:`Queries`
(Anfragen) entgegen und gibt Datensätze zurück.
* Für Abfragen von relationalen Datenbanken wurde die :mark:`Sprache SQL`
(Structured Query Language) entwickelt.
* :mark:`Python` stellt die Module ``mySQLdb`` und ``sqlite3`` zur Verfügung
um via SQL mit einer Datenbank zu kommunizieren.
..
Objektspeicherung - pickle
==========================
Das Modul :mark:`pickle` bietet komfortable Funktionen für das
:mark:`Abspeichern von Objekten`.
Aus dem Objekt wird ein :mark:`String` erzeugt welcher einfach
:mark:`abgespeichert und eingelesen` werden kann.
Beispiel Objekt speichern: ::
>>> import pickle
>>> f = open("test_pickle.txt", "w")
>>> pickle.dump([1, 2, 3], f)
Beispiel Objekt einlesen: ::
>>> import pickle
>>> f = open("test_pickle.txt")
>>> pickle.load(f)
[1, 2, 3]
..
Datenbanken
===========
:mark:`Große bzw. komplexe Datenmengen` benötigen entsprechende
:mark:`Verwaltungsprogramme`. Obige Konzepte sind dafür nur
bedingt geeignet. Man verwendet daher :mark:`Datenbanken`.
Bei einer Datenbank wird zwischen dem Programm und
dem Massenspeicher (Festplatte, ..) ein Zwischenlayer
(:mark:`Datenbanksystem`) eingeführt
(siehe Abbildung `Datenbankschnittstelle`_).
.. _`Datenbankschnittstelle`:
.. figure:: images/datenbank.png
:scale: 80 %
:align: center
Datenbankschnittstelle
Allgemeines:
* Das Datenbanksystem nimmt dabei Abfragen, sogenannte :mark:`Queries`
(Anfragen) entgegen und gibt Datensätze zurück.
* Hier verwenden wir :mark:`relationale Datenbanken`, die einen Datenbestand in
Tabellen organisieren.
* Für Abfragen von relationalen Datenbanken wurde die :mark:`Sprache SQL`
(Structured Query Language) entwickelt.
* :mark:`Python` stellt die Module ``mySQLdb`` und ``sqlite3`` zur Verfügung
um via SQL mit einer Datenbank zu kommunizieren.
Im Folgen werden wir ein einfaches Beispiel mit ``sqlite3`` machen.
Datenbank – sqlite3
-------------------
SQLite ist ein sehr :mark:`einfaches Datenbanksystem` und in Python integriert.
Hier ein Beispiel (``daten_sqlite3.py``, Daten von oben):
.. literalinclude:: src/daten_splite3.py
Ausgabe: ::
[(u'Porsche', u'911'), (u'Skoda', u'Octavia'), (u'Audi', u'Q3')]
Erklärungen:
* Im Allgemeinen laufen Datenbanken auf einem :mark:`Server` und ein :mark:`Client` muss sich mit diesem verbinden.
``sqlite3`` emuliert dieses Verhalten. Daher macht man zuerst ein ``connect`` zur Datenbasis.
* Um mit der Datenbank arbeiten zu können, braucht es einen sogenannte :mark:`Cursor` (Positionsanzeiger), analog zu einem Textverarbeitungsprogramm.
* Mit ``execute`` werden :mark:`SQL Befehle` abgesetzt. Alle großgeschriebenen Wörter sind Bestandteile der Sprache SQL.
* Werte können mit :mark:`Wildcards` (``?``) von Variablen übergeben werden.
* Die Werte befinden sich zunächst im Arbeitsspeicher, erst mit ``commit`` werden diese in die Datenbank geschrieben.
* Für die :mark:`Datenbankabfrage` wird der SQL Befehl ``SELECT`` verwendet.