Dictionary speichern laden

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
Mr_Martin
User
Beiträge: 9
Registriert: Samstag 5. Januar 2019, 19:39

Hallo zusammen,
Bin neu hier und versuch mich seit kurzem an Python. Vorkenntnisse von anderen Sprachen sind zumindest grundlegend vorhanden.

Ich habe jetzt ein kleines Projekt mit QPython 3 auf Android angefangen, in dem es letzten Endes um folgendes geht:

Benutzer soll eine Zahl eingeben und diese wird mit verschiedenen dict's abgeglichen. Ist die Zahl in einem der dict's vorhanden Soll ich der Wert dieses Eintrags um 1 erhöhen. Die dict's sollen am Ende gespeichert werden und auch als solche wieder lesbar sein.

Das mit dem Speichern und lesen will aber nicht so richtig funktionieren. Habe dazu jetzt schon einiges gefunden und getestet aber das Ergebnis waren entweder merkwürdige Zeichen bzw "0" in der Datei (hab's mit txt und bin versucht) oder Fehlermeldungen im Programm. Im Quelltext sind ein paar der Versuche mit # ausgeblendet (mit json und pickle).

#-*-coding:utf8;-*-
#qpy:3
#qpy:console
#import pickle
#import cPickle as pickle
#import json

#ah1 = open(/storage/emulated/0/Programmierung/test.txt, r")
ah1 = {1: 0, 2: 0}#, 3: 0, 4: 0, 5:0}
ah2 = {6: 0, 7: 0, 8: 0, 9: 0, 10:0}


#c_ah1 = ah1.values

#*******************************************
user_input = 100
while user_input > 0:

user_input = eval(input("welche zahl? "))

if user_input == 0:
break

elif user_input in ah1:

ah1[user_input] = ah1[user_input] +1
#ah1 = str(ah1)


elif user_input in ah2:

ah2[user_input] = ah2[user_input] +1
print("Falsche Eingabe")

with open("/storage/emulated/0/Programmierung/test.txt", "w") as save:
# user_input.write(pickle.dump(ah1))
# user_input.write(json.dump(ah1))
print(user_input, file=save)

print(ah1)
print(ah2)

Vielen Dank schon mal für eure Tipps
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Eingerückt wird mit 4 Leerzeichen pro Ebene, nicht 2. Die vielen Leerzeilen machen das Lesen schwierig.
Statt `user_input` mit einem Dummy-Wert zu belegen, solltest Du eine while-True-Schleife benutzen, zumal die Bedingung sowieso nie wahr wird, weil Du die Schleife vorher per break verläßt.
`eval` sollte nicht benutzt werden, `int` reicht hier. `json.dump` erwartet als Argument das Fileobjekt, was Dir auch die Fehlermeldug gesagt hätte, die Du hier am besten mit postest, wenn Du Fragen stellst.

Code: Alles auswählen

import json

ah1 = {1: 0, 2: 0}
ah2 = {6: 0, 7: 0, 8: 0, 9: 0, 10:0}

while True:
    user_input = int(input("welche zahl? "))
    if user_input == 0:
        break
    elif user_input in ah1:
        ah1[user_input] += 1
    elif user_input in ah2:
        ah2[user_input] += 1
    else:
        print("Falsche Eingabe")

with open("/storage/emulated/0/Programmierung/test.txt", "w") as save:
    json.dump(ah1, save)
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich würde die Kodierung beim `open()` explizit mit UTF-8 angeben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Mr_Martin
User
Beiträge: 9
Registriert: Samstag 5. Januar 2019, 19:39

Super. Danke für die schnelle Antwort. Da hab ich wohl einfach bisschen viel durcheinander gehauen ^^
Wollte mir da mit meinem Halbwissen irgendwie einen Weg durch suchen :D
Mr_Martin
User
Beiträge: 9
Registriert: Samstag 5. Januar 2019, 19:39

@_blackjack_:
Wenn ich den Startwert von ah1 oben im Programm gleich aus der (bestehenden) Datei herauslaufen will kommt folgender Fehler der mich glaube ich darauf verweist wenn ich das richtig verstehe.

TypeError: <_io.TextIOWrapper name ='/DATEIPFAD/Test.txt' mode='r' encoding='utf-8' > is Not json serializable

import json

ah1 = open("/storage/emulated/0/Programmierung/test.txt", "r")
#ah1 = {1: 0, 2: 0, .3: 0, 4: 0, 5:0}
ah2 = {6: 0, 7: 0, 8: 0, 9: 0, 10:0}


#c_ah1 = ah1.values

#*******************************************
user_input = 100
while True:

user_input = int(input("welche zahl? "))

if user_input == 0:
break

elif user_input in ah1:

ah1[user_input] = ah1[user_input] +1

elif user_input in ah2:

ah2[user_input] = ah2[user_input] +1

with open("/storage/emulated/0/Programmierung/test.txt", "w") as save:
json.dump(ah1, save)

print(ah1)


BTW: wie kann ich den Code richtig in einem Post platzieren? Bei den paar Zeilen geht das ja mal noch auch wenn's unschön aussieht aber wird ja unübersichtlich
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Code Tag ist der </> Button im vollständigen Editor.

Und beim serialisieren kommt’s auf die Reihenfolge deiner Argumente an.
Mr_Martin
User
Beiträge: 9
Registriert: Samstag 5. Januar 2019, 19:39

Danke ^^

Wenn ich die Argumente ('ah1' als dict und 'save' als datei) in meinem Programm vertausche kommt die gleiche Meldung.
Oder sind damit andere Argumente gemeint?
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mr_Martin: Du kannst ein Wörterbuch nicht einfach durch ein Dateiobjekt ersetzen. Das ``ah1 = open(…`` macht keinen Sinn. An der Stelle musst Du die Datei öffnen und dann den Inhalt der Datei mit `json.load()` laden und das daraus resultierende Wörterbuch an `ah1` binden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Mr_Martin
User
Beiträge: 9
Registriert: Samstag 5. Januar 2019, 19:39

Da wollte ich es mir wohl einfacher machen als es ist ^^

Code: Alles auswählen

with open("/storage/emulated/0/Programmierung/test.txt", "r") as nativ:
  ah1 = json.load(nativ)
Habe das jetzt am Programmanfang anstelle des dict's eingefügt. Das Laden funktioniert so auch super, nur ändert sich ah1 nicht mehr bei Eingabe einer Zahl. Gebunden wurde das Wörterbuch richtig an ah1 ( print(ah1) nach obigem code gibt das Wörterbuch richtig aus. Bleibt halt aber auch so wie es ist.

Danke für die Geduld mit einem Neuling ^^
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mr_Martin: Dann muss sich auch am weiteren Code irgendwas geändert haben, wenn der vorher funktioniert hat.

Die Anmerkungen zur Einrückung etc. könntest Du bei Gelegenheit auch umsetzen. Und zumindest bei neuem Code nicht weiterhin gegen die Konventionen programmieren.

Den Dateinamen würde man als Konstante definieren, statt ihn zweimal im Programm stehen zu haben.

Und bessere Namen als `ah1`, `ah2`, `nativ`, und `save`. Bei den ersten beiden wird nicht klar was sie überhaupt bedeuten wenn man das nicht sowieso schon weiss. Was `nativ` hier bedeuten soll ist mir nicht so ganz klar, und `save` ist ein Name für eine Funktion oder Methode, aber nicht für ein Dateiobjekt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Das liegt daran, das JSON nur Strings als Keys kennt. Warum sind denn die Keys Zahlen? Falls das also zwingend ist, mußt Du Schlüssel eben wieder in Zahlen umwandeln.
Mr_Martin
User
Beiträge: 9
Registriert: Samstag 5. Januar 2019, 19:39

Vielen Dank für die bisherigen Tipps.
Habe versucht so viel wie möglich davon umzusetzen.
Mit der Variablenbennennung tu ich mich immer noch bisschen schwer ^^
Die Einträge in den Wörterbüchern sind jetzt Strings (ich will nur die Werte ändern also ist das kein Problem)

Soweit hat das ganze dann auch schon mal mit Speichern und Laden funktioniert.
Jetzt wollte ich das ganze wie folgt in eine for Schleife packen um Änderungen der Dicts zu erleichtern und vor allem um nicht alles für jedes dict schreiben zu müssen.

Code: Alles auswählen

import json

index = ["ah1"]
while True:
  user_input = input("Welche zahl? ")
  if user_input == "0":
    break	
  else:
    for i in index:
      source = "/storage/emulated/0/Programmierung/Test_" + i + ".txt"
      data_r = open(source, "r")     
      data_w = open(source, "w")                                 
      with data_r as r:
       i = json.load(r)
      if user_input in i:
        i[user_input] += 1       
        with data_w as w:
          json.dump(i, w)
      else: print("Falsche Eingaben")
Bei "i = json.load(r) bringt er mir dann folgenden Fehler:
"valueerror no json object could be decoded"
Hier wollte ich das dict in die variable ah1 laden.
Die Variablen werden bis dahin soweit ich das erkennen konnte (mit print getestet) alle richtig übergeben.

Meine erste Frage dazu wäre: ist die Konstruktion prinzipiell so machbar oder hab ich mir de nur n Haufen Mist zusammengewürfelt? :D
Zu dem Fehler: Json scheint ja mit r nichts anfangen zu können wenn ich das richtig verstehe. Liegt der Fehler schon davor oder hab ich etwas vergessen? Oder ist das doch nur Müll so? ^^
"Falsche Eingabe" ist auch noch falsch platziert aber das ist erstmal nebensächlich.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

`i` ist ein schlechter Variablennamen, wie alle einbuchstabigen, weil sie nichts aussagen. Zudem benutzt Du `i` für verschiedene Werte in der selben Schleife. Die with-Statements werden seltsam verwendet, das open gehört ins with.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, nicht mal 2 und mal 1. Statt "0" wäre Leerstring einleuchtender als Abbruchkriterium.
Strings setzt man nicht mit + zusammen sondern nutzt Formatierung.
Zum Fehler: Deine Datei ist leer.
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Leer ist sie übrigens weil das öffnen mit 'w' die Datei leert. Zu dem Zeitpunkt weisst Du doch auch noch gar nicht ob in die Datei überhaupt geschrieben werden muss. Das sollte man also erst machen wenn das feststeht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Mr_Martin
User
Beiträge: 9
Registriert: Samstag 5. Januar 2019, 19:39

Für 'i' muss ich noch einen besseren Namen finden.
Aber ansonsten ist i doch nur dort wo es als ah1 bzw ah2 stehen soll oder irre ich mich da?
Mit dem with habe ich wirklich etwas quer gedacht ^^ würde verbessern (:
Habe jetzt (wenn nichts übersehen) überall 4 mal eingerückt, werd mich dran gewöhnen.
Abbruch Bedingung würde abgeändert. Mit der string-Formatierung müsste ich mich erstmal auseinandersetzen aber das Ergebnis scheint zu passen (:

Code: Alles auswählen

import json

index = ["ah1", "ah2"]
while True:
    user_input = input("Welche zahl? ")
    if user_input == "":
        break	
    else:
        for i in index:
            source = "/storage/emulated/0/Programmierung/Test_{0:1s}.txt".format(i)
            with open(source, "r") as data_r:
                i = json.load(data_r)                                                       
            print(i)
            if user_input in i:
                i[user_input] += 1       
                with open(source, "w") as data_w:
                    json.dump(i, data_w)
                print(i)
            else: print("Falsche Eingaben")
Zu der Datei: bei mir ist sie nich leer weil sie schon von den Versuchen davor beschrieben war, das hab ich nicht bedacht. Da werde ich vll noch ne Abfrage einarbeiten bei der die Datei erstellt wird, wenn keine vorhanden ist.
Inhalt der Datei wäre: {"1": 2, "3": 0, "2": 1, "5": 2, "4": 0}
Aber erstmal Versuch ich die "Falsche Eingabe" an die richtige Position zu bringen. Dass sie dort falsch ist weiß ich ja schon ^^
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Mr_Martin: Du verwendest `i` einmal für den Dateinamen(teil) und etwas später dann für den Dateinhalt.

Listen (und andere Sequenztypen oder auch iterierbare Objekte) werden üblicherweise in der Mehrzahl von dem benannt was für ein einzelnes Element ein guter Name wäre. Also vielleicht `index_names` statt `index`, dann kann man das erste `i` in `index_name` umbenennen und die zweite Verwendung von `i` dann vielleicht `index` wenn so ein Wörterbuch ein Index sein soll.

Statt `user_input` könnte man einen Namen verwenden der sagt was der Wert *bedeutet*, nicht wie er zustande gekommen ist.

Das ``:1s`` im Platzhalter beim formatieren ist überflüssig.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Mr_Martin
User
Beiträge: 9
Registriert: Samstag 5. Januar 2019, 19:39

Das "i" bin ich jetzt los geworden. Hab versucht die variable so wie beschrieben aufzuteilen. Das hat auch gleich mehr oder weniger gut funktioniert. (Ausgabe ist richtig aber doppelt)^^

Zum ausprobieren ist mir user_input erstmal noch aussagekräftig genug aber werd das noch ändern ;)

Wollte das mit dem Platzhalter einfach mal so ausprobieren weil es für mich eben neu ist aber hab mir schon gedacht dass ich mir das in dem Fall sparen kann (:
Antworten