Warum funktioniert das nicht?

Code-Stücke können hier veröffentlicht werden.
Antworten
schahramsigi
User
Beiträge: 13
Registriert: Sonntag 7. Juni 2020, 20:18

Hallo Forum,

Code: Alles auswählen

import csv

def main():
    with open("daten/freunde.csv", newline="", encoding="utf8") as lines:
        freunde = list(csv.reader(lines))

    with open("daten/freunde.csv", mode="a", newline="", encoding="utf8") as output:
        output = csv.writer(output)
        while True:
            eingabe = input("Eingabe: (q=quit n=neu) ").lower()
            if eingabe == "q":
                break
            elif eingabe == "n":
                vorname = input("Vorname? ").lower().strip()
                nachname = input("Nachname? ").lower().strip()
                neuer_freund = [vorname, nachname]
                if vorname and nachname:
                    if neuer_freund not in freunde:
                        freunde.append(neuer_freund)
                        output.writerow(neuer_freund)
                    else:
                        print("Exsistiert schon!")
                else:
                    print("Da fehlt was!")
            else:
                gefundene_freunde = []
                for vorname, nachname in freunde:						#For-Schleife
                    if vorname == eingabe or nachname == eingabe:
                        gefundene_freunde.append([vorname, nachname])
                if gefundene_freunde:
                    for vorname, nachname in gefundene_freunde:
                        print(vorname.title(), nachname.title())				#Print

if __name__ == "__main__":
    main()
wenn ich das laufen lasse bekomme ich folgende Fehlern:

Traceback (most recent call last):
File "/home/schahram/python/program.py", line 43, in <module>
main()
File "/home/schahram/python/program.py", line 33, in main
for vorname, nachname in liste:
ValueError: not enough values to unpack (expected 2, got 1)

Hilfe! Ich blicke nicht mehr durch.
Danke
Benutzeravatar
Dennis89
User
Beiträge: 1152
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

ich glaube du verwechselst eine Liste mit einem Dictonary.

Code: Alles auswählen

 names = ['Hans', 'Peter']
for name in names:
    print(name)
In Worte: Eine Liste mit dem Name 'names'. 'names' enthält zwei Strings: Hans, Peter.
Die Schleife: binde nacheinander jedes Objekt in der Liste an den Name 'name'. Das heißt die Schleife geht nacheinander jedes Objekt in der Liste durch. Dieses Objekt kann nach dem Doppelpunkt und der Einrückung mit dem Name 'name' verwendet werden. Dann geht es mit dem nächsten Objekt in der Liste weiter.
Du kannst für die einzelnen Objekte in der Liste beliebige Namen verwenden.

Es ist aber falsch zu denken, du könntest zum einen zwei Werte gleichzeitig aus deiner Schleife auslesen und zum anderen den Inhalt der Objekte mit den Namen anzusprechen, mit denen du die Liste erstellt hast.

Willst du auf einen bestimmten Listeneintrag zugreifen, dann kannst du das mit dem Index machen. 'names[1]' gibt zum Beispiel das zweite Objekt aus, also 'Peter'.

Schau dir mal Dictonarys in Python an, das könnte was für dich sein.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Fehlermeldung passt nicht zum gezeigten Code, es gibt keine Variable `liste` und keine Zeile 33.

Hast Du Dir mal die Liste `freunde` ausgeben lassen? Es gibt mindestens eine Zeile darin, die nicht dem entspricht, was Du erwartest.

@Dennis: das geht schon. Wenn Du eine Liste mit jeweils zweielementigen Einträgen hast, kannst Du sie in der for-Schleife genau so entpacken. Nennt sich Tuple-Unpacking, weil man das meist bei Tupeln macht. Bei schahramsigi besteht die Liste `freunde` aus den Einträgen [vorname, nachname]. Also alles richtig, bis auf das, dass die gelesenen Daten aus der csv-Datei nicht diesem Schema entsprechen.
Benutzeravatar
Dennis89
User
Beiträge: 1152
Registriert: Freitag 11. Dezember 2020, 15:13

Danke für den Hinweis, ich habe

Code: Alles auswählen

neuer_freund = [vorname, nachname]
                if vorname and nachname:
                    if neuer_freund not in freunde:
                        freunde.append(neuer_freund)
nicht ordentlich gelesen. Hier hätte ich den Aufbau der Liste erkennen sollen.


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
schahramsigi
User
Beiträge: 13
Registriert: Sonntag 7. Juni 2020, 20:18

Danke Sirius3

In der Datei freunde.csv fehlte tatsächlich etwas! In einem Eintrag fehlte eine Koma zwischen vorname und nachname.
Jetzt funktioniert es.

Gruß
Schahram
Benutzeravatar
__blackjack__
User
Beiträge: 13064
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@schahramsigi: Ist schon etwas älter, aber ich hätte noch Anmerkungen zum Quelltext im ersten Beitrag:

Daten wie den Dateipfad/-namen sollte man nur einmal im Quelltext stehen haben. Um Fehler zu vermeiden und Änderungen einfacher zu machen würde man den einmal am Anfang des Programms als Konstante definieren.

Das öffnen der Datei auf Vorrat ist keine so gute Idee. Auch wenn die Ressourcenverschwendung heutzutage nicht mehr so ins Gewicht fällt, braucht man nicht die ganze Zeit eine Datei offen halten. Und es macht es umständlicher beispielsweise die einzelnen Funktionalitäten in eigene Funktionen heraus zu ziehen.

Es ist etwas verwirrend sowohl die Ausgabedatei als auch das CSV-Writer-Objekt `output` zu nennen.

Zur Suchfunktion: ``if vorname == eingabe or nachname == eingabe`` kann man ohne die Wiederholung von `eingabe` auch mit ``in`` ausdrücken: ``if eingabe in [vorname, nachname]:``. Da man dann weder `vorname` noch `nachname` tatsächlich braucht wenn man damit sowieso nur wieder den Eintrag aus der Liste nachbaut, kann man die Schleife gleich über die Listen laufen lassen:

Code: Alles auswählen

            gefundene_freunde = []
            for freund in freunde:
                if eingabe in freund:
                    gefundene_freunde.append(freund)
Hier drängt sich dann auch eine „list comprehension“ auf:

Code: Alles auswählen

            gefundene_freunde = [
                freund for freund in freunde if eingabe in freund
            ]
Das ``if`` vor der Ausgabe ist überflüssig, denn wenn die Liste leer ist, dann wird die ``for``-Schleife auch ohne die zusätzliche Prüfung nicht durchlaufen.
Und wenn man diese Prüfung nicht macht, dann braucht man auch die Liste gar nicht erstellen, sondern kann daraus einen Generatorausdruck machen.

Das Programm kommt nicht damit klar falls die Datei noch gar nicht existiert.

Die Hauptfunktion ist dann schon etwas lang und hat zu viele Aufgaben. Das kann man schon sinnvoll auf Funktionen aufteilen.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import csv
from pathlib import Path

FREUNDE_DATEIPFAD = Path("daten", "freunde.csv")


def hole_eingabe(prompt):
    return input(prompt).strip().lower()


def lade_freunde():
    try:
        with FREUNDE_DATEIPFAD.open(newline="", encoding="utf8") as datei:
            return list(csv.reader(datei))
    except FileNotFoundError:
        return []


def freund_hinzufuegen(freunde):
    vorname = hole_eingabe("Vorname? ")
    nachname = hole_eingabe("Nachname? ")
    if vorname and nachname:
        neuer_freund = [vorname, nachname]
        if neuer_freund not in freunde:
            freunde.append(neuer_freund)
            with FREUNDE_DATEIPFAD.open(
                mode="a", newline="", encoding="utf8"
            ) as datei:
                csv.writer(datei).writerow(neuer_freund)
        else:
            print("Exsistiert schon!")
    else:
        print("Da fehlt was!")


def suche(freunde, eingabe):
    for vorname, nachname in (
        freund for freund in freunde if eingabe in freund
    ):
        print(vorname.title(), nachname.title())


def main():
    freunde = lade_freunde()
    while True:
        eingabe = hole_eingabe("Eingabe: (q=quit n=neu) >")
        if eingabe == "q":
            break

        if eingabe == "n":
            freund_hinzufuegen(freunde)
        else:
            suche(freunde, eingabe)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten