405 lines
10 KiB
Plaintext
405 lines
10 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%% md\n"
|
|
},
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"# Software Entwicklung \n",
|
|
"\n",
|
|
"## Kapitel 9: IO\n",
|
|
"\n",
|
|
"Unter *IO* (Input/Output) versteht man alle Mechanismen,\n",
|
|
"die mit dem Ausleiten von Daten aus einem Programm\n",
|
|
"bzw. dem Einlesen von Daten in ein Programm zusammenhängen."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%% md\n"
|
|
},
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"### 9.1 Zeichenkodierung\n",
|
|
"\n",
|
|
"Möchte ein Programm Daten senden (z.B. in eine Datei\n",
|
|
"oder über eine Netzwerkverbindung) oder diese empfangen,\n",
|
|
"werden letztendlich Bytes übertragen. Handelt es sich bei den\n",
|
|
"Daten um Text - also lesbare Zeichen - so muss durch eine\n",
|
|
"Zeichenkodierung (engl. *encoding*) festgelegt werden,\n",
|
|
"wie dieser Text auf Bytes abgebildet wird.\n",
|
|
"\n",
|
|
"Ein sehr übliches Kodierungsschema ist *UTF-8*. Darin werden\n",
|
|
"die Zahlen 0 bis 127 analog zum alten ASCII-Standard\n",
|
|
"insbesondere für grundlegende lateinische Zeichen in\n",
|
|
"Groß- und Kleinschrift verwendet. Alle übrigen Zeichen wie\n",
|
|
"z.B. deutsche Umlaute, chinesische Schriftzeichen,\n",
|
|
"Emojis etc. werden durch größere Zahlen ggf. mit mehreren\n",
|
|
"Bytes codiert. Die Zuordnung der Zahlen zu den Zeichen\n",
|
|
"ist durch den [*Unicode*-Standard](http://www.unicode.org/)\n",
|
|
"festgelegt."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"Möchte man eine Python-Zeichenkette in eine Unicode-Bytefolge\n",
|
|
"übertragen, so kann dafür die Methode <code>encode</code> der Klasse\n",
|
|
"*str* (String) verwendet werden."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%%\n"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"text = \"Nürnberg ist schön\"\n",
|
|
"print(f\"Länge {len(text)}\")\n",
|
|
"utf8 = text.encode(\"utf-8\")\n",
|
|
"print(utf8)\n",
|
|
"print(f\"Länge {len(utf8)}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "-"
|
|
}
|
|
},
|
|
"source": [
|
|
"Das vorangestellte <code>b</code> signalisiert, dass es sich\n",
|
|
"hier um eine Bytefolge handelt."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%%\n"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"print(type(utf8))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"Eine solche Bytefolge kann auch wieder in einen\n",
|
|
"Textstring verwandelt werden. Dazu besitzt die\n",
|
|
"Klasse *bytes* die Methode <code>decode</code>."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%%\n"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"decoded_text = utf8.decode(\"utf-8\")\n",
|
|
"print(decoded_text)\n",
|
|
"print(f\"Länge {len(decoded_text)}\")\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"### 9.2 Dateien\n",
|
|
"\n",
|
|
"Unter *Textdateien* verstehen wir Dateien, die\n",
|
|
"mit einem Texteditor erzeugt und bearbeitet werden können.\n",
|
|
"Der Inhalt sind lesbare Zeichen, die meist\n",
|
|
"in Zeilen organisiert sind. Um sie auf einem\n",
|
|
"Speichermedium abzulegen, müssen die Zeichen\n",
|
|
"in Bytes konvertiert bzw. beim Lesen\n",
|
|
"rückübertragen werden.\n",
|
|
"\n",
|
|
"*Binärdateien* sind Dateien, für die keine Kodierung\n",
|
|
"stattfinden soll (z.B. Bilder).\n",
|
|
"\n",
|
|
"Python besitzt bereits im Standard Funktionen, Klassen und Methoden,\n",
|
|
"die das Lesen und Schreiben von Dateien sowie das Übertragen\n",
|
|
"von Text in Bytes (und zurück) unterstützen."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"Einstiegspunkt ist die Built-In-Funktion <code>open</code>, die ein\n",
|
|
"Dateiobjekt zurückliefert. Die Parameter von <code>open</code> sind\n",
|
|
"der *Dateiname* (ggf. inkl. Pfad) und der *Bearbeitungsmodus*\n",
|
|
"sowie weitere, weniger gebräuchliche optionale Parameter.\n",
|
|
"\n",
|
|
"\n",
|
|
"| *Bearbeitungsmodus* | *Bedeutung* |\n",
|
|
"|:--------------------:|----------------------------------------------------|\n",
|
|
"| 'r' | Die Datei wird gelesen (muss bereits existieren) |\n",
|
|
"| 'w' | Die Datei wird geschrieben (vorhandene Datei wird überschrieben) |\n",
|
|
"| 'a' | Die Datei wird geschrieben (neuer Inhalt wird angehängt) |\n",
|
|
"| 'r+' | Die Datei wird gelesen und geschrieben |\n",
|
|
"\n",
|
|
"Standardmäßig finden die Lese- und Schreiboperationen mit der Standard-Kodierung des verwendeten Betriebssystems statt. Soll die Kodierung unterbleiben, muss an den Bearbeitungsmodus ein <code>'b'</code>\n",
|
|
"(für binär) angehängt werden."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%%\n"
|
|
},
|
|
"slideshow": {
|
|
"slide_type": "-"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"f = open(\"091a Textdatei\", \"r\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"Das auf diese Weise erhaltene Dateiobjekt kann für (je nach\n",
|
|
"Bearbeitungsmodus) für das Lesen und Schreiben benutzt werden.\n",
|
|
"Die Methode <code>read</code> ohne Angabe eines Parameter\n",
|
|
"liest den gesamten Inhalt der Datei ein\n",
|
|
"(Vorsicht: nur bei kleinen Dateien ratsam, da speicherintensiv)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%%\n"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"content = f.read()\n",
|
|
"print(content)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"Jedes geöffnete Dateiobjekt muss auch wieder geschlossen werden,\n",
|
|
"da andernfalls Betriebssystemressourcen dauerhaft belegt bleiben."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%%\n"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"print(f.closed)\n",
|
|
"f.close()\n",
|
|
"print(f.closed)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"Sollte eine Textdatei in einer anderen Kodierung als die Standard-Kodierung vorliegen, kann die gewünschte Kodierung mittels des Parameters <code>encoding</code> angegeben werden. Mit <code>encoding=None</code> wird wieder die Standard-Kodierung gewählt, was dem Standardwert und damit dem Weglassen des Parameters entspricht. Im folgenden Beispiel wird eine Textdatei geladen, die im UTF-8-Format vorliegt. Die Standard-Kodierung auf Windows weicht allerdings davon ab, wie man an den Umlauten erkennen kann."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"f = open(\"utf8_text\", \"r\", encoding=None)\n",
|
|
"content = f.read()\n",
|
|
"print(content)\n",
|
|
"f.close()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"### 9.3 Kontextmanager\n",
|
|
"\n",
|
|
"Die strenge Verpflichtung, jede Datei auch zu schließen, ist\n",
|
|
"gelegentlich nicht einfach zu erfüllen. Falls z.B. eine\n",
|
|
"Exception auftritt und die Abarbeitungsreihenfolge\n",
|
|
"abgebrochen wird, ist trotzdem *close* aufzurufen."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%%\n"
|
|
},
|
|
"slideshow": {
|
|
"slide_type": "-"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"try:\n",
|
|
" f = open(\"091a Textdatei\", \"r\")\n",
|
|
" z = 1 / 0\n",
|
|
" # f.close() würde nicht erreicht!\n",
|
|
"except:\n",
|
|
" print(\"Fehler!\")\n",
|
|
"finally:\n",
|
|
" f.close()\n",
|
|
"print(f.closed)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"Python bietet für dieses Problem den *Kontextmanager* an. Er\n",
|
|
"initialisiert einen *Kontext* für ein Objekt, führt einen\n",
|
|
"Codeblock in diesem Kontext aus und räumt beim Verlassen\n",
|
|
"des *Kontext* belegte Ressourcen auf.\n",
|
|
"\n",
|
|
"Das Schlüsselwort für den Beginn eines *Kontext* ist <code>with</code>."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"pycharm": {
|
|
"name": "#%%\n"
|
|
}
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"with open(\"091a Textdatei\", \"r\") as f:\n",
|
|
" print(f.read())\n",
|
|
" print(f.closed)\n",
|
|
"\n",
|
|
"print(f.closed)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"slideshow": {
|
|
"slide_type": "slide"
|
|
}
|
|
},
|
|
"source": [
|
|
"Wie ist das realisiert? Tatsächlich nutzt der\n",
|
|
"*Kontextmanager* die beiden *dunder*-Methoden\n",
|
|
"<code>\\_\\_entry\\_\\_</code> und <code>\\_\\_exit\\_\\_</code>.\n",
|
|
"Die Methode <code>\\_\\_entry\\_\\_</code> wird beim Betreten des\n",
|
|
"Kontext aufgerufen, die Methode <code>\\_\\_exit\\_\\_</code> beim\n",
|
|
"Verlassen oder beim Auftreten einer nicht behandelten Exception.\n",
|
|
"\n",
|
|
"Beim Datei-Objekt von Python wird in der\n",
|
|
"<code>\\_\\_exit\\_\\_</code>-Methode sichergestellt, dass die\n",
|
|
"Datei geschlossen wird.\n",
|
|
"\n",
|
|
"Durch Überschreiben der Methoden können auch eigene Klassen\n",
|
|
"sinnvoll mit einem *Kontextmanager* zusammenarbeiten.\n",
|
|
"\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"celltoolbar": "Slideshow",
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.9.9"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 1
|
|
}
|