Datein in eine Textdatei ein und auslesen

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
Tombery
User
Beiträge: 29
Registriert: Mittwoch 10. Juli 2019, 19:56

Leute ich brauch mal wieder eure Hilfe.
Ihr hat mir schon so sehr geholfen, dass das Hauptprogramm (welches eine Runde eines Kartenspiels simuliert) perfekt funktioniert.

Ich habe nun das ganze Hauptprogramm in eine Funktion geschrieben und rufe es in einer Schleife auf.
Die so erstellte Funktion hat als result Wert nur den Gewinner.
Diese Schleife befindet sich in meiner "Simulations"- Datei.

Das Problem ist nun, dass ich bestimmte Werte in eine Text Datei speichern muss???, sollte????, da ich später untersuchen will mit welchen Anfangskarten ich gewonnen oder verloren habe.

In meiner Vorstellung sollten in der Text-Datei die 4 Starthände der 4 Spieler in den ersten 4 Zeilen und in der fünften Zeile, welcher dieser Spieler gewonnen hat.

Soweit zur Theorie, leider bin ich noch immer ein recht blutiger Anfänger und weiß nicht ob das Format, das ich erzeugen will überhaupt sinnvoll ist.
Es sollte jedenfalls, so gespeichert werden, dass es für den Menschen lesbar ist.

Ich hab mich nun einige Stunden damit verbracht mit JSON en und decoder zu arbeiten.

Ich verstehe nicht wie man mehrere Sachen in eine Datei hineinschreiben kann.
Bei mir scheint es so zu sein, als würde er immer die Erste Zeile überschreiben.

Momentan sieht mein Versuch so aus.
Die Werte S1,S2,S3,S4 müssen zu einer anderen Zeit in die Datei geschrieben werden, als der Gewinner, da S1 bis S4 ja verändert wird.
Deswegen habe ich mir gedacht ich speicher das als 2 verschiedene Dateien ab.

Diese Funktionen werden an der entsprechenden Stelle in Main aufgerufen.

Code: Alles auswählen

def print_in_data_gewinner(gewinner):
    with open('Gewinner.txt', 'w') as filehandle:
        json.dump(gewinner, filehandle)




def print_in_data_hand(S1, S2, S3, S4):
    with open('Data.txt', 'w') as filehandle:
        json.dump(S1, filehandle)
        json.dump(S2, filehandle)
        json.dump(S3, filehandle)
        json.dump(S4, filehandle)


Welches Format würden ihr empfehlen? (Es muss ja wieder eingelesen werden)
Ist es sinnvoll 2 verschiedene Dateien dafür zu verwenden?
Wieso werden die Zeilen überschrieben und wie verhindere ich das?
nezzcarth
User
Beiträge: 1762
Registriert: Samstag 16. April 2011, 12:47

Wenn du den Inhalt einer Datei beim Schreiben erhalten möchtest, musst du den Modus "a" (append) verwenden. Als menschenlesbares Format kann man zum Beispiel Json-lines nehmen. Falls du dich damit anfreunden kannst, dass es nicht menschenlesbar ist, wäre vielleicht auch sqllite interesant, gerade auch dann, wenn du komplexere Abfragen auf den Daten machen möchtest. Von einem selbst ausgedachten Format würde ich eher absehen. Ich würde auch zusehen, dass eine Zeile einen vollständigen Datensatz repräsentiert, denn mehrzeilige Formate sind etwas aufwendiger einzulesen.
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tombery: Wenn man eine Datei mit 'w' öffnet wird eventuell vorhandener Dateiinhalt gelöscht. Man sollte in eine JSON-Datei auch entweder nur *einen* JSON-Wert speichern, oder dafür sorgen, das die Datei dem JSON Lines-Format entspricht. JSON ”pur” ist nicht für mehr als einen JSON-Wert pro Datei geeignet. Ich würde aber wahrscheinlich für Deinen Fall nicht zwei Dateien verwenden, sondern erst am *Ende* alle Daten in eine Datei schreiben. Dann musst Du Dir die Lage am Anfang halt merken.

Namen durchnummerieren ist in der Regel ein Zeichen das man etwas falsch macht. Entweder will man sich bessere Namen ausdenken, oder man will eigentlich gar keine einzelnen Namen vergeben, sondern eine Datenstruktur verwenden. Oft, und wohl auch in diesem Fall, eine Liste.

Ebenso einbuchstabige Namen wie `S`. Was soll das denn sein? Ein Name soll dem Leser verraten was der Wert bedeutet und nicht zum rätselraten zwingen.

`filehandle` ist ein komischer/falscher Name, denn das Objekt repräsentiert direkt die Datei.

Die Funktionsnamen sind auch irreführend. Da wird nichts gedruckt/ausgegeben, also kein `print_*` und was das `_in_data_` bedeuten soll, ist mir auch nicht klar. Sprachmix Englisch/Deutsch ist auch sehr unschön.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Tombery
User
Beiträge: 29
Registriert: Mittwoch 10. Juli 2019, 19:56

Danke!
Das umstellen auf den Modus a hat geholfen.

Wenn ich die Funktionen auf

Code: Alles auswählen

def print_in_data_gewinner(gewinner):
    with open('Data.txt', 'a') as filehandle:
        json.dump(gewinner, filehandle)



def print_in_data_hand(S1, S2, S3, S4):
    with open('Data.txt', 'a') as filehandle:
        json.dump(S1, filehandle)
        json.dump(S2, filehandle)
        json.dump(S3, filehandle)
        json.dump(S4, filehandle)
ändere, sieht mein momentaner Output so aus:

Code: Alles auswählen

[12, 12, 12, 11, 11, 10, 9, 9, 9, 9, 8, 8, 7, 7, 7, 6, 4, 3, 3, 0][12, 12, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 5, 5, 5, 4, 4, 2][12, 11, 11, 11, 10, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 6, 5, 2, 1, 0][12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 7, 6, 6, 6, 6, 5, 4, 3]"P2"[12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 8, 8, 7, 7, 5, 5, 3, 3, 2, 1][12, 12, 11, 11, 11, 11, 11, 9, 9, 8, 8, 7, 6, 6, 6, 5, 4, 3, 2, 0][12, 12, 12, 12, 11, 11, 9, 9, 9, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 0][12, 12, 12, 12, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 8, 8, 8, 8, 4, 4]"P4"
Das sieht ja schon mal ganz ordentlich aus aber ein einlesen Stelle ich mir schwierig vor, wenn diese nicht durch Kommas getrennt sind.
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tombery: Wie gesagt: Mehr als ein JSON-Wert pro Datei ist keine gute Idee, ausser man sorgt explizit dafür dass das Format JSON Lines entspricht. Und dann sollte man auch besser pro Zeile die gleichen Informationen speichern und nicht mal Hände und mal den Gewinner. Zudem wäre es schön wenn da nicht nur die Werte gespeichert werden, sondern auch was die bedeuten, also als JSON-Objekt mit sinnvollen Namen. Dann lässt sich das leichter auswerten und eventuell später auch durch weitere Elemente erweitern.

Als JSON Lines und als ein JSON-Objekt pro Spiel, würde das so aussehen:

Code: Alles auswählen

{"hands": [[12, 12, 12, 11, 11, 10, 9, 9, 9, 9, 8, 8, 7, 7, 7, 6, 4, 3, 3, 0], [12, 12, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 5, 5, 5, 4, 4, 2], [12, 11, 11, 11, 10, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 6, 5, 2, 1, 0], [12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 7, 6, 6, 6, 6, 5, 4, 3]], "winner": "P2"}
{"hands": [[12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 8, 8, 7, 7, 5, 5, 3, 3, 2, 1], [12, 12, 11, 11, 11, 11, 11, 9, 9, 8, 8, 7, 6, 6, 6, 5, 4, 3, 2, 0], [12, 12, 12, 12, 11, 11, 9, 9, 9, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 0], [12, 12, 12, 12, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 8, 8, 8, 8, 4, 4]], "winner": "P4"}
Da müsstest Du dir dann wie gesagt die Hände am Anfang bis zum Ende merken, und am Ende dann Hände + Gewinner in ein JSON-Objekt verpackt als eine Zeile an die Datei anhängen, *plus* Zeilenendezeichen.

Warum ist der Gewinner eine Zeichenkette mit einem P und einer Ziffer? Das P sagt ja wohl das es sich um einen Player handelt – klar wer sollte sonst Gewinner sein wenn nicht ein Mitspieler. Es wäre einfacher das P einfach weg zu lassen und den Index der Hand die gewonnen hat zu speichern, als *Zahl*. Also:

Code: Alles auswählen

{"hands": [[12, 12, 12, 11, 11, 10, 9, 9, 9, 9, 8, 8, 7, 7, 7, 6, 4, 3, 3, 0], [12, 12, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 7, 7, 5, 5, 5, 4, 4, 2], [12, 11, 11, 11, 10, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 6, 5, 2, 1, 0], [12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 7, 6, 6, 6, 6, 5, 4, 3]], "winner": 1}
{"hands": [[12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 8, 8, 7, 7, 5, 5, 3, 3, 2, 1], [12, 12, 11, 11, 11, 11, 11, 9, 9, 8, 8, 7, 6, 6, 6, 5, 4, 3, 2, 0], [12, 12, 12, 12, 11, 11, 9, 9, 9, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 0], [12, 12, 12, 12, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 8, 8, 8, 8, 4, 4]], "winner": 3}
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Tombery
User
Beiträge: 29
Registriert: Mittwoch 10. Juli 2019, 19:56

@_blackjack_
Ich habe versucht die Starthände festzuhalten bevor mit ihnen gespielt wird.
Dies habe ich mit

Code: Alles auswählen

S1 = P1
S2 = P2
S3 = P3
S4 = P4 
gemach.

Das S steht für Starthand und es war ein Versuch die Werte festzuhalten bevor sie sich verändern.
Komischerweise funktioniert das nicht. Mit dem P-Wert wird auch immer der S-Wert verändert und das wobei die oben genannte Zuweisung in keiner Schleife steht und die S Werte sonst nirgendwo vorkommen.
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

@Tombery: in Python sind Zuweisungen nur Kopien von Referenzen, die aber auf das gleiche Objekt verweisen. Wenn Du eine unabhängige Liste haben willst, mußt Du eine Kopie machen. Das ist aber eher unüblich. Normal ist, dass man statt die Px-Liste zu verändern eine neue zu erstellen.
Wenn Du anfängst, Variablennamen durchzunummerieren, machst Du etwas falsch, dann willst Du eigentlich eine Liste verwenden.
Tombery
User
Beiträge: 29
Registriert: Mittwoch 10. Juli 2019, 19:56

Achso, das sind nur Zuweisungen von Referenzen. Das erklärt so einiges. P1 bis P4 wird rein zufällig über einen Zufallsgenerator erzeugt. Ich habe keine andere Wahl, als irgendwie eine Kopie davon zu machen. Schließlich kann ich sie ja nicht einfach nochmal definieren.
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wenn `S` für `starthand` steht, dann schreib gefälligst auch `starthand`. Und weder sollte es vier nummerierte `S` oder `starthand` Namen geben, noch das gleiche mit `P` – was dann für `hand` steht‽
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Tombery
User
Beiträge: 29
Registriert: Mittwoch 10. Juli 2019, 19:56

Ich habe nun tatsächliche Kopien der Hände gemacht und damit hat es funktioniert.

Code: Alles auswählen

def write_in_data(S1,S2,S3,S4,gewinner):
    with open('Data.txt', 'a') as filehandle:
        Data = {'hands':[S1,S2,S3,S4], "winner": gewinner}
        json.dump(Data, filehandle)
Ich bekomme nun folgenden Output:

Code: Alles auswählen

{"hands": [[12, 12, 12, 11, 11, 10, 9, 8, 8, 7, 7, 7, 7, 7, 6, 4, 4, 4, 3, 0], [12, 12, 12, 12, 11, 11, 11, 10, 10, 10, 8, 8, 7, 7, 6, 5, 4, 3, 2, 0], [12, 12, 11, 11, 11, 11, 10, 10, 10, 9, 9, 8, 8, 6, 6, 5, 5, 3, 2, 1], [12, 12, 12, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, 6, 6, 5, 5]], "winner": 4}{"hands": [[12, 12, 12, 12, 11, 10, 10, 10, 9, 9, 8, 8, 7, 7, 6, 6, 4, 4, 1, 0], [12, 12, 12, 12, 11, 11, 10, 10, 10, 10, 8, 7, 7, 7, 6, 5, 5, 5, 3, 0], [12, 12, 12, 11, 11, 11, 11, 11, 10, 10, 8, 8, 6, 5, 5, 4, 3, 3, 2, 2], [12, 11, 11, 11, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 7, 7, 6, 6, 4]], "winner": 3}
Das ist zwar ganz schön, jedoch wäre es noch schöner wenn ich einen Zeilenumbruch zwischen den Durchläufen bekomme.
In Internet steht man soll das mit \n machen.
Jedoch weiß ich nicht recht wohin man das schreiben sollte, hab schon all mögliche Stellen ausprobiert.
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tombery: Das Zeilenende musst Du in die Datei schreiben. Nachdem das JSON da rein geschrieben wurde.

Textdateien sollte man immer explizit mit einer Kodierungsangabe öffnen. JSON selbst ist als ASCII spezifiziert, also wäre das eine sichere Angabe, denn `json.dump()` stellt mit den Defaultwerten ASCII sicher. In den Daten scheint ja auch nichts zu sein was mehr nötig machen würde. Die „JSON Lines“-Spezifikation schlägt für den Fall UTF-8 vor, weil das leichter zu lesen ist als Escape-Sequenzen.

Als Dateiendung wird .jsonl nahegelegt.

Was sind das denn für Karten und wie sind die kodiert?
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Tombery
User
Beiträge: 29
Registriert: Mittwoch 10. Juli 2019, 19:56

Das sind keine handelüblichen Karten, kodiert sind sie mit den Zahlen 0 bis 12.

Dankeschön!
Ich habs geschafft!

Mein code sieht nun so aus:

Code: Alles auswählen

def write_in_data(S1,S2,S3,S4,gewinner):
    with open('Data.json', 'a', encoding = 'utf-8') as f:
        Data = {'hands':[S1,S2,S3,S4], "winner": gewinner}
        json.dump(Data, f)
        f.write('\n')
Ich müsste das dann auch noch zur Auswertung in Excel einlesen.
Das ist mir erst jetzt eingefallen.
Ich habe gesehen es gibt JSON zu CSV online converter.
Werden die funktionieren wenn ich da jetzt Zeilenumbrüche einsetze?
Oder wäre es da generell gleich gescheiter eine 2 Funktion zu schreiben welche mir das als CSV verpackt ausgibt?
nezzcarth
User
Beiträge: 1762
Registriert: Samstag 16. April 2011, 12:47

Die Voraussetzung für CSV ist, dass deine Daten durchgängig dieselbe Spaltenanzahl haben. Wenn das gegeben ist (sah jetzt so aus), kannst du auch gleich CSV statt JSON rausschreiben. Dafür gibt es ein Modul in der Standardbibliothek. Wenn das nicht gegeben ist, lohnt sich das Konvertieren in einem sekundären Schritt, da du zuvor die maximale Spaltenzahl bestimmen und fehlende Spalten auffüllen musst.

Nebenbei: Es muss nicht immer unbedingt Excel sein (zumal Exel bei CSV Datein etwas störrisch sein kann). Wenn du uns sagst, was du vorhast, können wir dir evtl. sagen, ob/wie du das direkt in Python lösen kannst (z.B. mit dem 'statistics'-Modul aus der Standardbibliothek).
Tombery
User
Beiträge: 29
Registriert: Mittwoch 10. Juli 2019, 19:56

Die Spaltenzahl wird sich wohl nie verändern.
Ich habe vor ein Maß zu kreieren, welche mir die Güte der Hand angibt. Wie ich das jetzt genau machen werde führt etwas weit.
Ich brauch Excel um Diagramme und Tabellen erstellen zu können. Wobei ich Excel2LaTeX benutze, um dann die Tabellen in LaTeX darstellen zu können.
Mir ist gerade aufgefallen, dass es vermutlich besser wäre den Median und das arithmetische Mittel der Hände mit Python zu berechnen. Dann kann ich mir das auch in meine Ausgabedatei packen, so erspare ich mir das einzelne der einzelnen Karten in Excel.
Benutzeravatar
__blackjack__
User
Beiträge: 14045
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tombery: Diagramme kann man auch in Python erstellen, zum Beispiel mit Matplotlib und auch für LaTeX und LaTeX-Tabellen gibt es Module wie PyLaTeX.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten