# Objekt-orientierte Programmierung
Code mit vielen Eigenschaften kann schnell unübersichtlich werden - sogar selbst geschriebener Code altert schlecht und ist nach wenigen Wochen unlesbar. Was macht der folgende Code?
v = [
[["Baum", "tree"], 0, 0],
[["Blume", "flower"], 0, 0],
[["Fisch", "fish"], 0, 0],
]
for _ in range(3):
for w in v:
w1, w2 = w[0]
if w2 == input(f"Translate {w1}: "):
w[1]+=1
print("correct")
else:
w[2]+=1
print("incorrect")
for w in v:
print(f'{w[1]/(w[1]+w[2]):.0%}: {w[0]}')
Code wird nur einmal geschrieben, aber sehr viel häufiger und von mehr Personen gelesen. Es lohnt sich also, in leserlichen Code zu investieren. Natürlich könnten wir obigen _Spaghetti-Code_ mit besseren Variablennamen, Dictionaries und Kommentaren verbessern. Nur verlieren wir vor lauter Strings schnell den Überblick...
# Define vocabulary unit
voci_unit = [
{'translation': {'word1':"Baum", 'word2': "tree"}, 'correct': 0, 'incorrect': 0},
{'translation': {'word1':"Blume", 'word2': "flower"}, 'correct': 0, 'incorrect': 0},
{'translation': {'word1':"Fisch", 'word2': "fish"}, 'correct': 0, 'incorrect': 0},
]
# Make three passes
for _ in range(3):
for w in voci_unit:
if w['translation']['word2'] == input(f"Translate {w['translation']['word1']}: "):
w['correct']+=1
print("correct")
else:
w['incorrect']+=1
print("incorrect")
# Print statistics
for w in voci_unit:
print(f'{w['correct']/(w['correct']+w['incorrect']):.0%}: {w['translation']}')
Wouldn't it be nice... wenn wir unsere Lernprogramm ohne viel Kommentar und trotzdem kurz und verständlich definieren könnten?
Zum Beispiel so:
from voci import *
unit = VocabularyUnit([
WordPair('Baum', 'tree'),
WordPair('Blume', 'flower'),
WordPair('Fisch', 'fish')
])
learner = ConsoleLearner()
learner.learn(unit)
unit.print_stats()
## Klassen und Objekte
Genau das erreichen wir mit der **objekt-orientierten Programmierung**. Du hast bereits sehr oft Objekte benutzt, zum Beispiel Strings oder Listen. Ein Objekt gruppiert Attribute (en. _attributes_) und Methoden (Funktionen, die zum Objekt gehören). Alle Objekte einer _Klasse_ haben die gleichen Methoden und die gleichen Attribut-Namen, aber möglicherweise unterschiedliche Inhalte in den Attributen.
**Beispiel**: Alle Listen-Objekte enthalten eine Sequenz von Elementen, aber nicht dieselben. Die `pop`-Methode wird aber für alle Listen-Objekte das letzte Element entfernen und zurückgeben.
Eine Klasse wird in Python mit dem `class` Keyword definiert. Methoden haben immer einen ersten Paramter `self`, der für das konkrete Objekt steht, für das die Methode ausgeführt wird. Wird eine neues Objekt erstellt, wird zuerst die `__init__` Methode aufgerufen.
Am bestem am Beispiel:
class WordPair:
"""A word and its translation."""
def __init__(self, word1, word2):
"""Creates a new pair from two strings."""
self.word1 = word1 # All objects of class WordPair share the same attributes
self.word2 = word2 # but not necessarily the same contents.
def reversed(self): # All objects of class WordPair share the same methods
"""Returns a copy of the pair in the reverse direction."""
return WordPair(self.word2, self.word1)
tree = WordPair('Baum', 'tree') # we are passing only two arguments, the self argument is implicit.
print(f'{tree.word1} translates to {tree.word2}') # Attributes can be accessed using dot-notation.
### Aufgabe A
* Erstelle ein neues github-Repository `ksr_talit_vocabulary` und clone es lokal in VS Code.
* Teile es mit `tkilla77` und `anschae`.
* Füge das `.gitignore` für Python hinzu (von [[https://github.com/github/gitignore/blob/main/Python.gitignore|hier]]).
Erstelle eine neue Python-Datei `voci.py` und erstelle deine erste Klasse `WordPair` wie oben und zeige sie der Lehrperson. Achte auf:
* Coding-Conventions:
* Klassennamen in CamelCase
* Methoden und Attribute in lower_case_with_underscores()
* Dokumentation mit `"""doc strings"""`
Wir möchten zusätzlich eine Klasse `VocabularyUnit` haben, die eine Liste von `WordPairs` speichert.
Als drittes benötigen wir eine Klasse `ConsoleLearner` mit einer Methode `learn(unit)`, die alle WortPaare abfragt.
* um das Terminal zu leeren kannst du `print("\033c", end="")` benützen
* um die Zeile im Terminal zu löschen, verwendest du `print("\033[H\033[J", end="")`
* mehr dazu auf [[wp>ANSI_escape_code]]