Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| lehrkraefte:blc:informatik:glf22:python:woertlitrainer [2022/12/12 08:28] – [Besserer Programmierstil] Ivo Blöchliger | lehrkraefte:blc:informatik:glf22:python:woertlitrainer [2022/12/16 06:02] (current) – [Python Snippets] Ivo Blöchliger | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Wörtlitrainer ====== | ||
| + | |||
| + | ===== Pseudocode ===== | ||
| + | * **Input**: Liste von Wortpaaren (ebenfalls eine Liste). Z.B. | ||
| + | <code python> | ||
| + | voci = [ ["ein Byte", "un octet" | ||
| + | </ | ||
| + | * **Output**: Vorläufig keiner | ||
| + | * Für jedes '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * Wort auf Deutsch anzeigen | ||
| + | * Übersetzung vom Benutzer einlesen, in Variable '' | ||
| + | * Wenn '' | ||
| + | |||
| + | ===== Python-Snippets ===== | ||
| + | Testen, verändern und verstehen Sie folgende Mini-Programme: | ||
| + | |||
| + | Vokabular in verschachtelter Liste festlegen und auf einzelne Elemente zugreifen: | ||
| + | <code python> | ||
| + | voci = [ ["ein Byte", "un octet" | ||
| + | print(voci) | ||
| + | print(voci[0]) | ||
| + | print(voci[0][1]) | ||
| + | </ | ||
| + | |||
| + | Vokabular durchgehen: | ||
| + | <code python> | ||
| + | voci = [ ["ein Byte", "un octet" | ||
| + | for paar in voci: | ||
| + | print(paar) | ||
| + | print(f" | ||
| + | </ | ||
| + | |||
| + | Wort eingeben: | ||
| + | <code python> | ||
| + | import sys # sys einbinden | ||
| + | print(" | ||
| + | name = sys.stdin.readline().strip() | ||
| + | print(f" | ||
| + | </ | ||
| + | |||
| + | Wörter vergleichen: | ||
| + | <code python> | ||
| + | name = " | ||
| + | if name == " | ||
| + | | ||
| + | else: | ||
| + | | ||
| + | </ | ||
| + | |||
| + | <WRAP todo> | ||
| + | Programmieren Sie den Wörtli-Trainer in Python. | ||
| + | |||
| + | Hinweis: wenn '' | ||
| + | |||
| + | <hidden Lösungsvorschlag> | ||
| + | <code python> | ||
| + | import sys | ||
| + | voci = [ ["ein Byte", "un octet" | ||
| + | |||
| + | # Wiederholen, | ||
| + | for paar in voci: | ||
| + | ok = False # Benutzer hat noch nicht richtig geantwortet | ||
| + | anzahlfehler = 0 # Für dieses Wort, noch keinen Fehler | ||
| + | while not ok: | ||
| + | # Wort auf Deutsch anzeigen | ||
| + | print(f" | ||
| + | if anzahlfehler> | ||
| + | print(f" | ||
| + | # Eingabe vom Benutzer einlesen (Zeilenumbruch abschneiden mit strip) | ||
| + | eingabe = sys.stdin.readline().strip() | ||
| + | |||
| + | if eingabe==paar[1]: | ||
| + | ok = True # Damit wird die Schleife dann beendet | ||
| + | else: | ||
| + | anzahlfehler = anzahlfehler + 1 # Fehlerzähler erhöhen | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ====== Bessere Datenstruktur ====== | ||
| + | Dass das deutsche Wort über den Index '' | ||
| + | |||
| + | Es gibt in Python neben Arrays (von 0 bis $n-1$ durchnummerierte Einträge) auch Dictionaries, | ||
| + | |||
| + | <code python> | ||
| + | voci = [{" | ||
| + | {" | ||
| + | {" | ||
| + | print(" | ||
| + | print(voci) | ||
| + | print(" | ||
| + | print(voci[1]) | ||
| + | print(" | ||
| + | print(voci[1][" | ||
| + | |||
| + | </ | ||
| + | <WRAP todo> | ||
| + | Passen Sie Ihren Wörtli-Trainer an die neue Datenstruktur an. | ||
| + | </ | ||
| + | ===== JSON-Dateien ===== | ||
| + | JSON (JavaScript Object Notation) ist eine im Web-Bereich häufig verwendete Art, strukturierte Daten zu speichern. Diese kann auch sehr einfach in Python gelesen und geschrieben werden. Für Arrays und Dictionaries ist der Syntax sogar gleich. Diese Dateien können damit auch sehr einfach von Menschen gelesen und bearbeitet werden. Diverse Programmiersprachen (auch Python) haben bereits Bibliotheken, | ||
| + | |||
| + | JSON-Datei schreiben: | ||
| + | <code python> | ||
| + | import json | ||
| + | voci = [{" | ||
| + | {" | ||
| + | {" | ||
| + | with open(" | ||
| + | f.write(json.dumps(voci, | ||
| + | f.write(" | ||
| + | </ | ||
| + | <WRAP todo> | ||
| + | Führen Sie obiges Programm aus und betrachten Sie dann die generierte Datei '' | ||
| + | </ | ||
| + | |||
| + | |||
| + | JSON-Datei lesen (dieses Programm funktioniert erst, wenn die Datei voci.json korrekt erzeugt wurde): | ||
| + | <code python> | ||
| + | import json | ||
| + | with open(" | ||
| + | voci = json.loads(f.read()) | ||
| + | | ||
| + | # Jetzt kann mit der Variablen voci wie vorhin gearbeitet werden: | ||
| + | print(voci) | ||
| + | </ | ||
| + | |||
| + | <WRAP todo> | ||
| + | Passen Ihren Wörtli-Trainer so an, dass die Wörter von der Datei '' | ||
| + | </ | ||
| + | |||
| + | ===== Frei wählbare Datei ===== | ||
| + | Ziel ist es, die Wörter-Datei frei wählen zu können. Dies soll direkt auf der Kommandozeile geschehen: | ||
| + | |||
| + | <code python> | ||
| + | import os | ||
| + | import sys | ||
| + | |||
| + | datei = " | ||
| + | if len(sys.argv)> | ||
| + | datei = sys.argv[1] | ||
| + | print(datei) | ||
| + | if not os.path.exists(datei): | ||
| + | print(f" | ||
| + | exit(-1) | ||
| + | |||
| + | |||
| + | </ | ||
| + | <WRAP todo> | ||
| + | Testen Sie obiges Programm auch auf der Kommandozeile und geben Sie existierende und nicht existierende Dateien als Argument an (Sie können auch mit VSCode den Startknopf drücken, und dann in der internen Kommandozeile mit Pfeil nach oben das Kommando nochmals holen und eine Datei als Argument hinten hinzufügen). | ||
| + | </ | ||
| + | |||
| + | <WRAP todo> | ||
| + | Bauen Sie die Möglichkeit, | ||
| + | </ | ||
| + | |||
| + | |||
| + | <hidden Lösungsvorschlag> | ||
| + | <code pyton voci-mit-dict-von-datei.py> | ||
| + | import sys | ||
| + | import os | ||
| + | import json | ||
| + | |||
| + | ################## | ||
| + | # Daten einlesen # | ||
| + | ################## | ||
| + | |||
| + | # Datei bestimmen (default oder von der Kommandozeile) | ||
| + | datei = " | ||
| + | if len(sys.argv)> | ||
| + | datei = sys.argv[1] | ||
| + | print(f" | ||
| + | if not os.path.exists(datei): | ||
| + | print(f" | ||
| + | exit(-1) | ||
| + | |||
| + | # Daten einlesen | ||
| + | with open(datei, " | ||
| + | voci = json.loads(f.read()) | ||
| + | |||
| + | ########## | ||
| + | # Lernen # | ||
| + | ########## | ||
| + | |||
| + | # Wiederholen, | ||
| + | for paar in voci: | ||
| + | ok = False # Benutzer hat noch nicht richtig geantwortet | ||
| + | anzahlfehler = 0 | ||
| + | while not ok: | ||
| + | # Wort auf Deutsch anzeigen | ||
| + | print(f" | ||
| + | if anzahlfehler> | ||
| + | print(f" | ||
| + | # Eingabe vom Benutzer | ||
| + | eingabe = sys.stdin.readline().strip() | ||
| + | |||
| + | if eingabe==paar[' | ||
| + | ok = True | ||
| + | else: | ||
| + | anzahlfehler = anzahlfehler + 1 | ||
| + | </ | ||
| + | </ | ||
| + | ====== Intelligenteres Abfragen ====== | ||
| + | Wörter, die man schon gut kann, sollten nicht (oder kaum) abgefragt werden. Andere sollten hingegen häufiger abgefragt werden. Auch sollte die Reihenfolge der Wörter zufällig sein. | ||
| + | |||
| + | Dazu gibt es verschiedenste Ansätze. Ein ganz einfacher ist folgender: | ||
| + | * Zu jedem Wortpaar wird zusätzlich ein Score '' | ||
| + | * Ganz am Anfang sind alle Scores 0 | ||
| + | * Hat man das Wort richtig, wird '' | ||
| + | * Hat man das Wort falsch, wird '' | ||
| + | * Das Programm soll erst Wörter mit kleinstem Score abfragen. | ||
| + | |||
| + | ===== Python Snippets ===== | ||
| + | Zusätzliches Feld hinzufügen: | ||
| + | <code python> | ||
| + | voci = [{" | ||
| + | {" | ||
| + | {" | ||
| + | for paar in voci: | ||
| + | if not " | ||
| + | paar[" | ||
| + | print(voci) | ||
| + | </ | ||
| + | |||
| + | Ein zufälliges Wort aus allen Wörtern mit kleinstem Score kann wie folgt ausgewählt werden (was noch viel effizienter gemacht werden könnte): | ||
| + | * Wir sortieren alle Wörter, kleinste Scores zuerst (plus eine Zufallszahl zwischen 0 und 1, damit die Reihenfolge bei gleichem Score zufällig wird). | ||
| + | * Wir wählen das erste Wort aus | ||
| + | Sämtliche Wörter zu sortieren ist «overkill», | ||
| + | |||
| + | <code python> | ||
| + | import random | ||
| + | voci = [{' | ||
| + | |||
| + | for i in range(10): | ||
| + | # Vokabular sortieren, wobei ein Eintrag mit score+zufallszahl bewertet wird: | ||
| + | voci.sort(key = lambda eintrag: eintrag[' | ||
| + | print(f" | ||
| + | </ | ||
| + | |||
| + | ====== Endfassung ====== | ||
| + | <WRAP todo> | ||
| + | Erweitern Sie Ihr Programm schrittweise wie folgt und testen Sie es fortlaufend: | ||
| + | * Anstatt die Wörter der Reihe nach durchzugehen, | ||
| + | * Das Score soll angepasst werden, je nach Antwort. | ||
| + | * Das Programm soll beendet werden, wenn man ein z.B. nur ein ' | ||
| + | * Wenn das Programm beendet wird, sollen die Daten wieder geschrieben werden, damit die Scores erhalten bleiben. | ||
| + | * Erstellen Sie eine JSON-Datei mit dem aktuellen Französisch-Vokubular (gerne auch kollaborativ, | ||
| + | |||
| + | <hidden Lösungsvorschlag> | ||
| + | <code python voci-v1.py> | ||
| + | import sys | ||
| + | import os | ||
| + | import json | ||
| + | import random | ||
| + | |||
| + | ################## | ||
| + | # Daten einlesen # | ||
| + | ################## | ||
| + | |||
| + | # Datei bestimmen (default oder von der Kommandozeile) | ||
| + | datei = " | ||
| + | if len(sys.argv)> | ||
| + | datei = sys.argv[1] | ||
| + | print(f" | ||
| + | if not os.path.exists(datei): | ||
| + | print(f" | ||
| + | exit(-1) | ||
| + | |||
| + | # Daten einlesen | ||
| + | with open(datei, " | ||
| + | voci = json.loads(f.read()) | ||
| + | |||
| + | # Scores hinzufügen, | ||
| + | for paar in voci: | ||
| + | if not " | ||
| + | paar[" | ||
| + | |||
| + | ########## | ||
| + | # Lernen # | ||
| + | ########## | ||
| + | |||
| + | # Wiederholen, | ||
| + | programmEnde = False | ||
| + | print(" | ||
| + | while not programmEnde: | ||
| + | # Wörter Sortieren: | ||
| + | voci = sorted(voci, | ||
| + | # Aktuelles paar ist das erste in der Liste | ||
| + | paar = voci[0] | ||
| + | # Abfrage vorbereiten | ||
| + | ok = False # Benutzer hat noch nicht richtig geantwortet | ||
| + | anzahlfehler = 0 | ||
| + | while not ok: # Wiederholen, | ||
| + | # Wort auf Deutsch anzeigen | ||
| + | print(f" | ||
| + | if anzahlfehler> | ||
| + | print(f" | ||
| + | # Eingabe vom Benutzer | ||
| + | eingabe = sys.stdin.readline().strip() | ||
| + | if eingabe==" | ||
| + | programmEnde = True | ||
| + | break # innere while-Schlaufe verlassen | ||
| + | |||
| + | if eingabe==paar[' | ||
| + | ok = True | ||
| + | if anzahlfehler==0: | ||
| + | paar[' | ||
| + | elif anzahlfehler==1: | ||
| + | paar[' | ||
| + | else: | ||
| + | paar[' | ||
| + | if (paar[' | ||
| + | paar[' | ||
| + | else: | ||
| + | anzahlfehler = anzahlfehler + 1 | ||
| + | |||
| + | # Daten speichern: | ||
| + | with open(datei, " | ||
| + | f.write(json.dumps(voci, | ||
| + | f.write(" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ====== Besserer Programmierstil ====== | ||
| + | Im Moment ist das Programm ein schon ziemlich unübersichtlicher Klumpen. Um das Programm übersichtlicher zu gestalten, werden wir einzelne Programmteile in Funktionen auslagern, damit das Programm am Schluss in 3 Zeilen passt: | ||
| + | |||
| + | <code python> | ||
| + | voci, datei = daten_einlesen() | ||
| + | abfragen(voci) | ||
| + | daten_speichern(voci, | ||
| + | </ | ||
| + | |||
| + | Dazu gibt es einen [[https:// | ||
| + | |||
| + | <hidden Lösungsvorschlag> | ||
| + | <code python voci-refactored.py> | ||
| + | import sys | ||
| + | import os | ||
| + | import json | ||
| + | import random | ||
| + | |||
| + | ################## | ||
| + | # Daten einlesen # | ||
| + | ################## | ||
| + | |||
| + | def dateinamen_bestimmen(): | ||
| + | datei = " | ||
| + | if len(sys.argv)> | ||
| + | datei = sys.argv[1] | ||
| + | print(f" | ||
| + | if not os.path.exists(datei): | ||
| + | print(f" | ||
| + | exit(-1) | ||
| + | return datei | ||
| + | |||
| + | |||
| + | def scores_hinzufuegen(voci): | ||
| + | for paar in voci: | ||
| + | if not " | ||
| + | paar[" | ||
| + | |||
| + | |||
| + | def daten_einlesen(): | ||
| + | # Datei bestimmen (default oder von der Kommandozeile) | ||
| + | dateinamen = dateinamen_bestimmen() | ||
| + | # Daten einlesen | ||
| + | with open(dateinamen, | ||
| + | voci = json.loads(f.read()) | ||
| + | # Scores hinzufügen, | ||
| + | scores_hinzufuegen(voci) | ||
| + | return voci, dateinamen | ||
| + | |||
| + | |||
| + | ########## | ||
| + | # Lernen # | ||
| + | ########## | ||
| + | |||
| + | def hole_eingabe(paar, | ||
| + | # Wort auf Deutsch anzeigen | ||
| + | print(f" | ||
| + | if anzahlfehler> | ||
| + | print(f" | ||
| + | # Eingabe vom Benutzer | ||
| + | return sys.stdin.readline().strip() | ||
| + | |||
| + | |||
| + | def wort_korrekt(eingabe, | ||
| + | if eingabe != paar[' | ||
| + | return False # Funktion sofort beenden | ||
| + | # Eingabe ist korrekt | ||
| + | if anzahlfehler> | ||
| + | paar[' | ||
| + | if (paar[' | ||
| + | paar[' | ||
| + | return True | ||
| + | paar[' | ||
| + | return True | ||
| + | |||
| + | |||
| + | def wort_abfragen(paar): | ||
| + | anzahlfehler = 0 | ||
| + | while True: # Endlos Schleife | ||
| + | eingabe = hole_eingabe(paar, | ||
| + | if eingabe==" | ||
| + | return True # Programmabbruch | ||
| + | if wort_korrekt(eingabe, | ||
| + | return False # Wort korrekt, aber Programm nicht beenden | ||
| + | anzahlfehler = anzahlfehler + 1 | ||
| + | |||
| + | |||
| + | def wort_bestimmen(voci): | ||
| + | voci.sort(key = lambda eintrag: eintrag[' | ||
| + | # Aktuelles paar ist das erste in der Liste | ||
| + | return voci[0] | ||
| + | |||
| + | |||
| + | def abfragen(voci): | ||
| + | while True: # Endlosschleife | ||
| + | paar = wort_bestimmen(voci) | ||
| + | programmAbbruch = wort_abfragen(paar) | ||
| + | if programmAbbruch: | ||
| + | return | ||
| + | |||
| + | |||
| + | def daten_speichern(voci, | ||
| + | with open(dateinamen, | ||
| + | f.write(json.dumps(voci, | ||
| + | f.write(" | ||
| + | |||
| + | |||
| + | voci, dateiname = daten_einlesen() | ||
| + | abfragen(voci) | ||
| + | daten_speichern(voci, | ||
| + | </ | ||
| + | </ | ||