Vocabeltrainer

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Gödel
User
Beiträge: 20
Registriert: Samstag 16. April 2022, 15:32

Hallo, ich hätte eine Frage zu meinem Code, da er nicht ganz so funktioniert wie ich mir das vorstelle. Man kann alles eingeben und so, allerdings checkt das Programm nicht ob die Eingabe richtig war oder falsch sondern geht einfach direkt zu der Antwort für falsch. Kann mir vielleicht jemand helfen?

Code: Alles auswählen

import csv
i= 0
j= 0
data_list = []
data_dic = {}
file = open("Vocabeln.txt", "r")
csv_reader = csv.reader(file, delimiter=",")
for row in csv_reader:
   data_list.append(row)
for i in range(len(data_list)):
    for j in range(0,2):
        if j == 1:
            data_dic[data_list[i][j-1]] = data_list[i][j]

    
file.close()
i = 0
for i in range(len(data_dic)):
    key = data_list[i][0]
    user_input = input(f'{key}. What´s the german word?\n>')
    if user_input == data_dic[key]:
        print('Correct')
    else:
        print('Wrong! Correct word:', data_dic[key])
    
Danke schonmal für die Antworten
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Man definiert keine Variablen einfach so auf Vorrat. `i` und `j ` werden mit 0 initialisiert, dieser Wert wird aber nie benutzt.
Variabelnnamen sollten aussagekräftig sein und keine Abkürzungen oder Typen enthalten.
Über einen Index iteriert man nicht, wenn man auch direkt über die Elemente der Liste iterieren könnte, oder wie hier, das Erzeugen der Liste gleich ganz bleiben zu lassen und statt dessen direkt über das reader-Objekt zu iterieren. Die innere for-Schleife ist dann noch unsinniger, weil die über 0 und 1 geht aber nur bei 1 etwas macht.
Dateien öffnet man innerhalb eines with-Statements. csv-Dateien brauchen mit newline="" geöffnete Dateien.

Code: Alles auswählen

import csv

with open("Vocabeln.txt", newline="") as file:
    reader = csv.reader(file, delimiter=",")
    vocabulary = {
        english: german
        for english, german in reader
    }

for english, german in vocabulary.items():
    user_input = input(f'{english}. What´s the german word?\n>')
    if user_input == german:
        print('Correct')
    else:
        print('Wrong! Correct word:', german)
Bis Du sicher, dass Du das Wort exakt so eingegeben hast, wie erwartet wird?
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Gödel: Die am Anfang definierten Werte für `i` und `j` werden nirgends verwendet, die Defintionen machen also keinen Sinn und können weg. Das gilt auch für das ``i = 0`` vor der Abfrageschleife.

`data_list` und `data_dic` werden zu früh definiert. Man definiert Namen erst wenn sie gebraucht werden, und nicht alle am Anfang. Das macht es schwieriger den Code zu verstehen wenn man bei der ersten Verwendung eines Namens erst wieder am Anfang suchen muss, wie der definiert wurde. Wenn das Programm grösser wird und man viel am Anfang ”auf Vorrat” definiert hat, übersieht man gerne mal unbenutzte Namen, die entweder gar nicht oder nach Überarbeitung weiter unten im Code nicht mehr verwendet werden. Es ist auch aufwändiger Code aus einer Funktion die zu gross geworden ist, in kleinere Funktionen heraus zu ziehen, wenn man sich den Code erst zusammensuchen muss, wenn Code der eigentlich zusammengehört nicht in zusammenhängenden Zeilen steht.

Grunddatentypen haben in Namen nichts zu suchen. Der Leser will in der Regel nicht wissen ob er eine Liste oder ein Wörterbuch vor sich hat, sondern was die Werte darin bedeuten. Also `data_list` wäre beispielsweise `rows` und `data_dic` beispielsweise `english_to_german`.

Dateien sollte man wo möglich mit der ``with``-Anweisung vewenden, damit sie garantiert wieder geschlossen werden, wenn der ``with``-Block verlassen wird. Das schliessen steht momentan auch an einer etwas unerwarteten Stelle weil Leerzeilen so etwas wie zusammenhängende Schritte trennen. Und der erste Zeilenblock wäre „Daten einlesen“ und der zweite „Vokabeln abfragen“ und da würde das Schliessen der Datei zum einlesen gehören und nicht zum abfragen.

Bei Textdateien sollte man immer explizit die Kodierung beim öffnen angeben, sonst verhält sich das Programm bei unterschiedlichen Systemen anders. Wenn man die Kodierung selbst in der Hand hat, würde ich UTF-8 wählen, falls es keinen sinnvollen Grund für etwas anderes gibt.

Das `csv`-Modul erwartet das Dateien mit dem Argument ``newline=""`` geöffnet werden. Siehe Dokumentation.

Eine leere Liste erstellen und dann in einer Schleife die Elemente aus einem iterierbaren Objekt anzuhängen ist unnötig umständlich. Da ruft man einfach `list()` mit dem iterierbaren Objekt auf:

Code: Alles auswählen

        rows = []
        for row in csv.reader(file):
            rows.append(row)

        # =>

        rows = list(csv.reader(file))
Beim füllen des Wörterbuchs ist die innere Schleife unsinnig. Die läuft immer zwei mal, einmal mit j=0 und einmal mit j=1, aber nur wenn `j` den Wert 1 hat wird überhaupt etwas gemacht, das heisst es braucht da überhaupt gar keine Schleife und auch kein `j` weil man ja weiss, dass das 1 ist und j-1 dann 0 ist und man direkt die Zahlwerte dort hinschreiben könnte:

Code: Alles auswählen

        for j in range(0, 2):
            if j == 1:
                english_to_german[rows[i][j - 1]] = rows[i][j]

        # =>
        
        english_to_german[rows[i][0]] = rows[i][1]
Code der Art ``for i in range(len(sequence)):`` ist in Python ein „anti pattern“ weil man direkt über die Elemente von `sequence` iterieren kann, ohne den Umweg über einen Laufindex. Also:

Code: Alles auswählen

    for i in range(len(rows)):
        english_to_german[rows[i][0]] = rows[i][1]

    # =>
    
    for row in rows:
        english_to_german[row[0]] = row[1]
Aber auch bei `row` braucht man keinen Indexzugriff, weil man schon beim iterieren die beiden Werte an sinnvolle Namen binden kann:

Code: Alles auswählen

    for row in rows:
        english_to_german[row[0]] = row[1]
    
    # =>
    
    for english, german in rows:
        english_to_german[english] = german
Aber es geht noch einfach, denn genau wie `list()` ein iterierbares Objekt mit Elementen entgegen nimmt, kann man `dict()` ein iterierbares Objekt mit Schlüssel/Wert-Paaren übergeben, also in diesem Fall einfach `rows`. Und das muss auch keine Liste sein, die man danach ja sowieso nicht mehr braucht, sondern man kann da auch gleich das Reader-Objekt übergeben.

Auch bei der Abfrageschleife ist der Index wieder unnötig, und das hier immer noch die Liste verwendet wird, obwohl alle Informationen auch im Wörterbuch stecken ist redundant und damit im Grunde falsch.

In der Schleife braucht man immer zusammengehörige Schlüssel/Wert-Paare, also das was die `items()`-Methde auf Wörterbüchern liefert. Oder, da hier nirgends ein Zugriff über den Schlüssel erforderlich ist, speichert man es einfach in einer Liste.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import csv


def main():
    with open("Vocabeln.txt", "r", encoding="utf-8", newline="") as file:
        translations = list(csv.reader(file))

    for english, german in translations:
        user_input = input(f"{english}. What´s the german word?\n>")
        if user_input == german:
            print("Correct")
        else:
            print("Wrong! Correct word:", german)


if __name__ == "__main__":
    main()
Man müsste die Daten noch nicht einmal in einer Liste speichern, weil man die ``for``-Schleife auch direkt über das Reader-Objekt laufen lassen könnte.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
Gödel
User
Beiträge: 20
Registriert: Samstag 16. April 2022, 15:32

Ok wow, danke! Das wusste ich nicht, dass man eine Schleife direkt über das Reader-Objekt laufen lassen kann. Danke!

Allerdings funktioniert es irgendwie immer noch nicht. Ich erhalte immer noch(Bin ich irgendwie zu blöd?):

Code: Alles auswählen

sculpture. What´s the german word?
>Skulptur
Wrong! Correct word:  Skulptur
|Ich habe den Code überschrieben, also das ist der Output den ich erhalte bei dem den Sie geschickt haben|
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Vergleiche mal genau, was Du eingegeben hast, mit dem, was erwartet wird. Dazu hilft es, die Stringrepräsentation auszugeben:

Code: Alles auswählen

print(repr(user_input), repr(german))
Benutzeravatar
Gödel
User
Beiträge: 20
Registriert: Samstag 16. April 2022, 15:32

Jap, ich bin zu blöd. Danke ich hab den Fehler gefunden!
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wenn ich raten müsste sind in der Datei extra Leerzeichen drin gewesen, also " Skulptur" statt "Skulptur".
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten