Dictionary mit numpy arrays in Text-Datei schreiben

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

Hallo,

ich habe ein relativ großes Dictionary mit einigen Arrays bzw. Matrizen und würde dieses gerne in eine Textdatei schreiben.

Ich habe das Ganze erstmal so umgesetzt:

Code: Alles auswählen

def text_file(dict):
    text = open(filename.replace((filename[filename.rfind("."):]),'.txt'),'w')
    text.write(str(dict))
    text.close()
Das funktioniert soweit schon mal ganz gut. Das Problem ist nur, dass wenn ich mein Dictionary in die Textdatei schreiben will, werden die Arrays mittendrin durch "..." abgekürzt. Das selbe passiert auch, wenn ich es durch Print ausgeben will.. Innerhalb des Programms funktioniert aber alles richtig. Ich habe schon ein bisschen rumprobiert, aber leider keine Lösung gefunden. Ich arbeite im Python Interface eines FE Post-Prozessor unter Python 3.6. Hoffe jemand kann mir helfen.

Gruß
Marvin
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du einen String kürzen willst, ist wohl der umständlichste Weg, erst den Teil per Slicing herauszuholen und dann per Replace genau diesen Teil wieder zu suchen:

Code: Alles auswählen

filename[:filename.rfind(".")] + '.txt'
Aber statt mit Indizes zu arbeiten, nimmt man besser höhere Funktionen:

Code: Alles auswählen

filename.rsplit('.', 1)[0] + '.txt'
Da es sich aber um einen Dateinamen handelt, ist es noch besser mit pathlib zu arbeiten.

Code: Alles auswählen

pathlib.Path(filename).stem + '.txt'
Die Stringrepräsentation eines Wörterbuchs, bzw. den darin enthaltenen numpy-Arrays ist für Debuggingzwecke gedacht, nicht zum Speichern.
Es gibt keinen Standardweg um numpy-Arrays zusammen in einem Wörterbuch als Text-Datei zu speichern. Dazu mußt Du ein eigenes Format erfinden, bzw. die Arrays in Listen umwandeln und als JSON speichern.

PS: weder `text_file` als Funktionsnamen noch `dict` als Argument sind gute Namen. Funktionen sollten nach Tätigkeiten benannt werden `save_dict_as_text`. `filename` kommt aus dem Nichts, sollte aber ein Argument der Funktion sein.
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

Sirius3 hat geschrieben: Samstag 4. Mai 2019, 17:02 Wenn Du einen String kürzen willst, ist wohl der umständlichste Weg, erst den Teil per Slicing herauszuholen und dann per Replace genau diesen Teil wieder zu suchen:

Code: Alles auswählen

filename[:filename.rfind(".")] + '.txt'
Aber statt mit Indizes zu arbeiten, nimmt man besser höhere Funktionen:

Code: Alles auswählen

filename.rsplit('.', 1)[0] + '.txt'
Da es sich aber um einen Dateinamen handelt, ist es noch besser mit pathlib zu arbeiten.

Code: Alles auswählen

pathlib.Path(filename).stem + '.txt'
Ja ist etwas umständlich wie ich das gemacht habe. Komme bei diesen Dingen teilweise noch etwas durcheinander und da es funktioniert hat, habe ich nicht weiter dran rumgespielt. Pathlib funktioniert bei mir nicht.
Sirius3 hat geschrieben: Samstag 4. Mai 2019, 17:02 Die Stringrepräsentation eines Wörterbuchs, bzw. den darin enthaltenen numpy-Arrays ist für Debuggingzwecke gedacht, nicht zum Speichern.
Es gibt keinen Standardweg um numpy-Arrays zusammen in einem Wörterbuch als Text-Datei zu speichern. Dazu mußt Du ein eigenes Format erfinden, bzw. die Arrays in Listen umwandeln und als JSON speichern.
Okay, hätte gedacht, dass es da eine einfache Möglichkeit gibt. Habe das jetzt so gemacht:

Code: Alles auswählen

def save_dict_as_text(dict=dict_results):
    text = open((filename.rsplit('.', 1)[0] + '.txt'),'w')
    for result_name in dict:
        if result_name == "time":
            text.write(result_name)
            text.write(str(dict[result_name]))
        else:
            text.write(result_name)
            for element in range(len(dict[result_name])):
                result = str(dict[result_name][element])
                text.write(result)
    text.close()
Sirius3 hat geschrieben: Samstag 4. Mai 2019, 17:02 PS: weder `text_file` als Funktionsnamen noch `dict` als Argument sind gute Namen. Funktionen sollten nach Tätigkeiten benannt werden `save_dict_as_text`. `filename` kommt aus dem Nichts, sollte aber ein Argument der Funktion sein.
Ja Namen sind bei mir immer etwas schwierig. Ich habe das halt dict genannt, weil ich im Programm unterschiedliche Dictionaries verwende und das ja sowieso nur der Name innerhalb der Funktion ist. Filename verwende ich bereits an anderen Stellen meines Programms.

Code: Alles auswählen

fileinfo = models.info(model)
filename = str(fileinfo.name)
Benutzeravatar
__blackjack__
User
Beiträge: 13102
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marvin93: Alles was eine Funktion ausser Konstanten benötigt sollte als Argument(e) übergeben werden. Und wenn es eine Konstante ist, dann wird der Name KOMPLETT_GROSS geschrieben. Sie den Style Guide for Python Code.

Und so wie Du `filename` definierst scheint das keine Konstante zu sein. Und damit sollte es ein Argument sein. Den Dateinamen kann man auch an mehr als eine Funktion als Argument übergeben, wenn man den woanders auch noch mal braucht. Das ist also kein Argument dafür den zu einer globalen Variable zu machen. Zudem sollte der Dateiname der übergeben wird, ausch schon der tatsächliche Dateiname sein. Es ist nicht die Aufgabe einer Speichern-Funktion eine Dateierweiterung auszutauschen. Das fällt in den Aufgabenbereich des Aufrufers.

Warum funktioniert bei Dir `pathlib` nicht? Das wäre komisch wenn das bei allen aus Dir funktioniert. Und selbst wenn `pathlib` aus irgendwelchen komischen Gründen nicht funktioniert, ist das ein Pfad und dafür gibt es Funktionen in `os.path`. Zum Beispiel `os.path.splitext()` um die Dateierweiterung abzutrennen.

Warum willst Du das Wörterbuch mit den Arrays/Matrizen denn in eine Datei schreiben? Wenn das irgend wann einmal wieder von einem Programm verarbeiten werden soll, dann machst Du das falsch. Dafür verwendet man standardisierte Formate für die es Bibliotheken zum schreiben und lesen gibt, und erfindet nicht selbst ein Format. HDF5 könnte sich hier eventuell anbieten.

Wie kann man denn bei der Definition der Funktion schon ein `dict_results` als Default-Wert haben? Das sieht extrem falsch aus.

`text` ist kein so prickelnder Name für ein Dateiobjekt.

Beim öffnen von Textdateien sollte man immer explizit eine Kodierung angeben. Sonst kann man unangenehme Überraschungen erleben wenn man das mal auf einem anderen Rechner ausführt, oder mit anderen Systemeinstellungen die die Sprache/Kodierung betreffen.

Die äusssere ``for``-Schleife kann man gleich über die `items()` laufen lassen, denn in der Schleife werden ja in jedem Fall Schlüssel *und* Wert benötigt.

Die innere ``for``-Schleife ist in Python ein „anti pattern“. Statt mit ``for i in range(len(sequence)):` über den Umweg über einen Index auf die Elemente zuzugreifen, kann man auch *direkt* über die Elemente der Sequenz iterieren. Der Name `element` den Du für den *Index* des Elements verwendest ist an der Stelle auch sehr verwirrend, denn da würde man als Leser das Element selbst als Wert erwarten. Und dann kann man `str()` per `map()` auf die Elemente anwenden und die `writelines()`-Methode verwenden, und schon braucht man gar keine ``for``-Schleife mehr für den ``else``-Zweig selber schreiben.

Bei Dateien sollte man wenn es geht die ``with``-Anweisung verwenden, um ein Schliessen in jedem Fall zu garantieren.

In beiden Zweigen des ``if``/``else`` wird als erstes die gleiche Anweisung ausgeführt – die gehört also gar nicht dort rein, sondern *einmal* *vor* dieses Konstrukt.

Ungetestet:

Code: Alles auswählen

def save_dict_as_text(filename, data):
    with open(filename, 'w', encoding='ASCII') as file:
        for key, value in data.items():
            file.write(key)
            if key == 'time':
                file.write(str(value))
            else:
                file.writelines(map(str, value))
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Marvin93: was willst Du eigentlich erreichen? Alle Werte in einer Zeile ohne Leerraum hintereinander scheint mir nicht sehr sinnvoll.
Und auch hier ist die Stringrepräsentation von Zeilen einer Matrix eigentlich nicht für die dauerhafte Speicherung gedacht, zumal auch hier, bei zu langen Zeilen wieder ... ausgegeben wird.
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

__blackjack__ hat geschrieben: Samstag 4. Mai 2019, 20:18 @Marvin93: Alles was eine Funktion ausser Konstanten benötigt sollte als Argument(e) übergeben werden. Und wenn es eine Konstante ist, dann wird der Name KOMPLETT_GROSS geschrieben. Sie den Style Guide for Python Code.

Und so wie Du `filename` definierst scheint das keine Konstante zu sein. Und damit sollte es ein Argument sein. Den Dateinamen kann man auch an mehr als eine Funktion als Argument übergeben, wenn man den woanders auch noch mal braucht. Das ist also kein Argument dafür den zu einer globalen Variable zu machen. Zudem sollte der Dateiname der übergeben wird, ausch schon der tatsächliche Dateiname sein. Es ist nicht die Aufgabe einer Speichern-Funktion eine Dateierweiterung auszutauschen. Das fällt in den Aufgabenbereich des Aufrufers.

Warum funktioniert bei Dir `pathlib` nicht? Das wäre komisch wenn das bei allen aus Dir funktioniert. Und selbst wenn `pathlib` aus irgendwelchen komischen Gründen nicht funktioniert, ist das ein Pfad und dafür gibt es Funktionen in `os.path`. Zum Beispiel `os.path.splitext()` um die Dateierweiterung abzutrennen.
Also mein Programm wird nicht einfach so verwendet, sondern nur innerhalb eines FE Post-Prozessors. Die Funktionen werden also nicht irgendwo innerhalb des Programms aufgerufen, sondern immer nur bei Bedarf innerhalb des Post-Prozessors. Ich will da einfach möglichst wenige Argumente übergeben müssen. Der Name der Textdatei soll genau der gleiche sein wie der Name von der FE Simulation. Filename ist in dem Fall nicht nur der Name, sondern der gesamte Path inklusive Name. Warum pathlib nicht funktioniert, weiß ich nicht. os.path klappt, gibt mir aber den Path zu Python, nicht zu der FE Simulation die ich geöffnet habe.
__blackjack__ hat geschrieben: Samstag 4. Mai 2019, 20:18 Warum willst Du das Wörterbuch mit den Arrays/Matrizen denn in eine Datei schreiben? Wenn das irgend wann einmal wieder von einem Programm verarbeiten werden soll, dann machst Du das falsch. Dafür verwendet man standardisierte Formate für die es Bibliotheken zum schreiben und lesen gibt, und erfindet nicht selbst ein Format. HDF5 könnte sich hier eventuell anbieten.

Wie kann man denn bei der Definition der Funktion schon ein `dict_results` als Default-Wert haben? Das sieht extrem falsch aus.
Ja genau das ist der Plan. Im Prinzip will ich durch mein Programm einfach nur schnell an verschiedene Results kommen. Also beispielsweise die mechanische Spannung innerhalb des Teils. Daraus erstelle ich verschiedene Plots usw.. Und wenn der User das dann möchte, soll er diese Results dann auch noch in eine Textdatei schreiben können. Also das Dictionary für die Results gibt es dann zu dem Zeitpunkt logischerweise schon. Das ganze soll das später ggf. weiterverarbeitet werden.
Die Formate kenne ich nicht. Kann ich mit HDF5 das Dictionary direkt in eine Datei schreiben?
__blackjack__ hat geschrieben: Samstag 4. Mai 2019, 20:18 Beim öffnen von Textdateien sollte man immer explizit eine Kodierung angeben. Sonst kann man unangenehme Überraschungen erleben wenn man das mal auf einem anderen Rechner ausführt, oder mit anderen Systemeinstellungen die die Sprache/Kodierung betreffen.
Okay, danke. Ich wusste nicht, dass das Probleme machen kann.
__blackjack__ hat geschrieben: Samstag 4. Mai 2019, 20:18 Die äusssere ``for``-Schleife kann man gleich über die `items()` laufen lassen, denn in der Schleife werden ja in jedem Fall Schlüssel *und* Wert benötigt.

Die innere ``for``-Schleife ist in Python ein „anti pattern“. Statt mit ``for i in range(len(sequence)):` über den Umweg über einen Index auf die Elemente zuzugreifen, kann man auch *direkt* über die Elemente der Sequenz iterieren. Der Name `element` den Du für den *Index* des Elements verwendest ist an der Stelle auch sehr verwirrend, denn da würde man als Leser das Element selbst als Wert erwarten. Und dann kann man `str()` per `map()` auf die Elemente anwenden und die `writelines()`-Methode verwenden, und schon braucht man gar keine ``for``-Schleife mehr für den ``else``-Zweig selber schreiben.

Bei Dateien sollte man wenn es geht die ``with``-Anweisung verwenden, um ein Schliessen in jedem Fall zu garantieren.

In beiden Zweigen des ``if``/``else`` wird als erstes die gleiche Anweisung ausgeführt – die gehört also gar nicht dort rein, sondern *einmal* *vor* dieses Konstrukt.

Ungetestet:

Code: Alles auswählen

def save_dict_as_text(filename, data):
    with open(filename, 'w', encoding='ASCII') as file:
        for key, value in data.items():
            file.write(key)
            if key == 'time':
                file.write(str(value))
            else:
                file.writelines(map(str, value))
Okay, das sieht definitiv eleganter aus. Den Namen Element habe ich einfach genommen, weil es sich tatsächlich um Finite Elemente handelt. Das ist also einfach die Anzahl der Elemente in dem Bauteil. Ich kenne halt diese ganzen Funktionen nicht und versuche immer alles irgendwie durch google umzusetzen. Was genau hat meine Lösung denn für Nachteile? Der code funktioniert sehr gut, vielen Dank.
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

Sirius3 hat geschrieben: Samstag 4. Mai 2019, 20:44 @Marvin93: was willst Du eigentlich erreichen? Alle Werte in einer Zeile ohne Leerraum hintereinander scheint mir nicht sehr sinnvoll.
Und auch hier ist die Stringrepräsentation von Zeilen einer Matrix eigentlich nicht für die dauerhafte Speicherung gedacht, zumal auch hier, bei zu langen Zeilen wieder ... ausgegeben wird.
Ich suche einfach nach einer Lösung die Daten in eine Textdatei oder ähnliches zu schreiben und dann irgendwann weiterzuverarbeiten. Ich bin ehrlich gesagt nicht davon ausgegangen, dass das so kompliziert wird. Ich bin davon ausgegangen, dass man Dictionaries ganz simpel in eine Textdatei schreiben und dann wieder auslesen kann.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Eventuell möchtest du dir mal das Modul pickle anschauen
https://docs.python.org/3/library/pickle.html

Numpy ndarrays kann man direkt speichern und laden.
https://docs.scipy.org/doc/numpy/refere ... .save.html
https://docs.scipy.org/doc/numpy/refere ... numpy.load
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13102
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marvin93: Ob das als Programm oder in einem anderen Programm läuft, ändert nichts daran das globale Variablen nicht gut sind, und das Funktionen und Methoden alles was sie benötigen als Argument(e) übergeben bekommen. Es geht darum das der Code leicht nachvollziehbar, testbar, und weniger fehleranfällig ist. Das sollte grundsätzlich ein Ziel sein.

Was ist denn der Vorteil den Dateinamen nicht als Argument zu übergeben sondern ”magisch” irgendwo aus der Umgebung zu nehmen?

Wenn Du nicht weisst warum `pathlib` nicht funktioniert, kannst Du es ja nicht verwendet haben, denn dann wüsstest Du ja konkret was nicht funktioniert. Und das `os.path` die den Pfad zu Python gibt ist unsinnig. Das ist ein Modul, das gibt Dir gar nichts, und wenn Du die Funktionen daraus verwendet hast, und dabei ein falsches Ergebnis bekommst, dann hast Du offensichtlich etwas falsch gemacht.

Wenn die Daten später weiterverarbeitet werden sollen, dann bist Du auf dem falschen Weg da irgendwas komisches eigenes als Datenformat zu basteln. Das ist fehleranfällig und macht nur unnötig Arbeit. Zudem hat Sirius3 ja schon darauf hingewiesen das die Auslassungspunkte (``...``) mit dem bisherigen Programm nur scheinbar weg sind. Du hast nicht verhindert das die nicht doch wieder auftauchen. Entweder wenn die Arraygrösse wächst, oder wenn die Voreinstellung ab wann die `str()`-Repräsentation durch Auslassungspunkte verkürzt wird, sich ändert. Zum Beispiel weil eine andere Version von Numpy zum Einsatz kommt, oder eine andere Bibliothek oder Umgebung in der das läuft, diese Grenze verändert. Die Zeichenkettendarstellung von Numpy-Arrays ist nicht zur Speicherung oder vollständigen Darstellung gedacht, sondern als Ausgabe für Menschen zum lesen. Und da macht ein riesiges Array keinen Sinn, sondern verbraucht nur unnötig Speicherplatz und Rechenzeit. Weswegen die Ausgabe verkürzt wird.

HDF5 ist ein verbreitetes Dateiformat in dem man Arrays und Metadaten in einem hierarchisch organisiertem Format speichern kann. So ähnlich wie in einem Dateisystem. Mann kann da nicht direkt ein Wörterbuch rein schreiben, aber es sollte einfach sein ein Wörterbuch auf eine HDF5-Struktur abzubilden – und umgekehrt.

Man kann Wörterbücher nicht einfach in Textdateien schreiben, weil die Zeichenkettendarstellung von Python-Datentypen nicht dafür gedacht ist. Du musst ja auch über die Umkehrung nachdenken: Was dachtest Du denn wie Du das wieder einliest?

Man kann mit dem `pickle`-Modul Objekte serialisieren, dass wäre dann aber nicht ”lesbar” und man kann das auch nur mit Python wieder einlesen. Das ist praktisch um Objekte kurzfristig zu speichern oder zu übertragen, zum Beispiel für einen Cache oder wenn man Daten über Prozesse hinweg ”live” austauschen möchte. Das ist aber nicht so gut für eine langfristige Speicherung geeignet.

Als Textdateiformat könnte noch JSON in Frage kommen, dann musst Du aber selbst was schreiben um Datentypen zu (de)serialisieren die das `json`-Modul nicht schon von Haus aus kennt. Das könnte auch problematisch werden wenn die Arrays gross sind.

Die Erklärung mit den Finite Elementen verstehe ich nicht, auch da ist doch `element` immer noch ein falscher Name für den *Index*, denn der ist ja nicht das Element, sondern der Wert der an diesem Index steht.

Ich denke die Nachteile sind offensichtlich – meine Funktion macht effektiv genau das was Deine macht. Ich habe da ja nichts anderes geschrieben, sondern nur den ganzen unnötigen Kram weg gelassen. Und da kommt weniger, klarerer Code bei heraus. Das ist vielleicht so ein bisschen die Frage was es für Nachteile hat bei einer Formel nicht gemeinsame Faktoren heraus zu ziehen, Brüche zu kürzen, und Konstanten zu verrechnen. Der Code ist das Ergebnis einer schrittweisen Vereinfachung.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

ThomasL hat geschrieben: Sonntag 5. Mai 2019, 15:19 Eventuell möchtest du dir mal das Modul pickle anschauen
https://docs.python.org/3/library/pickle.html

Numpy ndarrays kann man direkt speichern und laden.
https://docs.scipy.org/doc/numpy/refere ... .save.html
https://docs.scipy.org/doc/numpy/refere ... numpy.load
Okay, vielen Dank. Mit pickle scheint das sehr einfach zu funktionieren. Klappt Perfekt. Ich habe das ganze jetzt so umgesetzt:

Code: Alles auswählen

def save_dict_pickle(data):
    pickle_out = open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"wb")
    pickle.dump(data, pickle_out)
    pickle_out.close()
    
def load_dict_pickle():
    pickle_in = open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"rb")
    data = pickle.load(pickle_in)
    for key, value in data.items():
        dict_results[key] = value
Würde das für quasi unendlich große dictionaries und numpy arrays funktionieren?
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Marvin93 hat geschrieben: Montag 6. Mai 2019, 15:09

Code: Alles auswählen

def save_dict_pickle(data):
    pickle_out = open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"wb")
    pickle.dump(data, pickle_out)
    pickle_out.close()
    
def load_dict_pickle():
    pickle_in = open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"rb")
    data = pickle.load(pickle_in)
    for key, value in data.items():
        dict_results[key] = value
Würde das für quasi unendlich große dictionaries und numpy arrays funktionieren?
Zuerst die Frage: pickle serialisiert und speichert ein Objekt im Speicher deines Rechners. Wenn du also unendlichen großen RAM hast, dann Ja, ansonsten Nein.

Dein Code wird mit dem "with" Kontextmanager noch eleganter.
Die Load Funktion ist fehlerhaft da dict_results undefiniert ist

Code: Alles auswählen

def save_dict_pickle(data):
    with open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"wb") as pickle_out:
        pickle.dump(data, pickle_out)
    
def load_dict_pickle():
    with open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"rb") as pickle_in:
    data = pickle.load(pickle_in)
    return data
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

__blackjack__ hat geschrieben: Sonntag 5. Mai 2019, 15:31 @Marvin93: Ob das als Programm oder in einem anderen Programm läuft, ändert nichts daran das globale Variablen nicht gut sind, und das Funktionen und Methoden alles was sie benötigen als Argument(e) übergeben bekommen. Es geht darum das der Code leicht nachvollziehbar, testbar, und weniger fehleranfällig ist. Das sollte grundsätzlich ein Ziel sein.

Was ist denn der Vorteil den Dateinamen nicht als Argument zu übergeben sondern ”magisch” irgendwo aus der Umgebung zu nehmen?
Naja so muss ich den Path noch mit eintippern. Ich will aber, dass die Textdatei einfach im selben Ordner unter dem selben Namen gespeichert wird.
__blackjack__ hat geschrieben: Sonntag 5. Mai 2019, 15:31 Wenn Du nicht weisst warum `pathlib` nicht funktioniert, kannst Du es ja nicht verwendet haben, denn dann wüsstest Du ja konkret was nicht funktioniert. Und das `os.path` die den Pfad zu Python gibt ist unsinnig. Das ist ein Modul, das gibt Dir gar nichts, und wenn Du die Funktionen daraus verwendet hast, und dabei ein falsches Ergebnis bekommst, dann hast Du offensichtlich etwas falsch gemacht.
Ich wusste nicht, dass ich pathlib noch importieren muss. Also es funktioniert und gibt mir auch den richtigen Namen. print(os.path) gibt mir aber nur den Path zum python ordner innerhalb des Ordners vom Post Prozessor. Wenn man damit noch irgendwas anderes machen kann, dann wusste ich das nicht.
__blackjack__ hat geschrieben: Sonntag 5. Mai 2019, 15:31 Wenn die Daten später weiterverarbeitet werden sollen, dann bist Du auf dem falschen Weg da irgendwas komisches eigenes als Datenformat zu basteln. Das ist fehleranfällig und macht nur unnötig Arbeit. Zudem hat Sirius3 ja schon darauf hingewiesen das die Auslassungspunkte (``...``) mit dem bisherigen Programm nur scheinbar weg sind. Du hast nicht verhindert das die nicht doch wieder auftauchen. Entweder wenn die Arraygrösse wächst, oder wenn die Voreinstellung ab wann die `str()`-Repräsentation durch Auslassungspunkte verkürzt wird, sich ändert. Zum Beispiel weil eine andere Version von Numpy zum Einsatz kommt, oder eine andere Bibliothek oder Umgebung in der das läuft, diese Grenze verändert. Die Zeichenkettendarstellung von Numpy-Arrays ist nicht zur Speicherung oder vollständigen Darstellung gedacht, sondern als Ausgabe für Menschen zum lesen. Und da macht ein riesiges Array keinen Sinn, sondern verbraucht nur unnötig Speicherplatz und Rechenzeit. Weswegen die Ausgabe verkürzt wird.

HDF5 ist ein verbreitetes Dateiformat in dem man Arrays und Metadaten in einem hierarchisch organisiertem Format speichern kann. So ähnlich wie in einem Dateisystem. Mann kann da nicht direkt ein Wörterbuch rein schreiben, aber es sollte einfach sein ein Wörterbuch auf eine HDF5-Struktur abzubilden – und umgekehrt.

Man kann Wörterbücher nicht einfach in Textdateien schreiben, weil die Zeichenkettendarstellung von Python-Datentypen nicht dafür gedacht ist. Du musst ja auch über die Umkehrung nachdenken: Was dachtest Du denn wie Du das wieder einliest?

Man kann mit dem `pickle`-Modul Objekte serialisieren, dass wäre dann aber nicht ”lesbar” und man kann das auch nur mit Python wieder einlesen. Das ist praktisch um Objekte kurzfristig zu speichern oder zu übertragen, zum Beispiel für einen Cache oder wenn man Daten über Prozesse hinweg ”live” austauschen möchte. Das ist aber nicht so gut für eine langfristige Speicherung geeignet.

Als Textdateiformat könnte noch JSON in Frage kommen, dann musst Du aber selbst was schreiben um Datentypen zu (de)serialisieren die das `json`-Modul nicht schon von Haus aus kennt. Das könnte auch problematisch werden wenn die Arrays gross sind.
Ja also das einfach als String in eine Textdatei zu schreiben habe ich auch aufgegeben. Ich hab ehrlich gesagt auch keine Lust eine Funktion zu schreiben die diesen riesigen String dann wieder in ein Dictionary umwandelt beim Einladen der Textdatei. Allein deswegen lass ich das jetzt.

Ich werde mir das HDF5 nochmal anschauen. Habe jetzt eine gut funktionierende Lösung mit pickle und eine mit JSON gefunden. Es funktioniert jeweils das speichern und einlesen. Die JSON Dateien werden allerdings sehr groß. In meinem Fall jetzt ca. 13 mal größer als die Pickle datei und 4 mal größer als die normale Textdatei. Werde mir HDF5 nochmal anschauen und es ansonsten einfach bei der Pickle Lösung belassen.
__blackjack__ hat geschrieben: Sonntag 5. Mai 2019, 15:31 Die Erklärung mit den Finite Elementen verstehe ich nicht, auch da ist doch `element` immer noch ein falscher Name für den *Index*, denn der ist ja nicht das Element, sondern der Wert der an diesem Index steht.
Naja ich hab den Index einfach Element genannt, weil es sich ja um die tatsächlichen Elemente handelt. Also ich habe für eine ein key im Wörterbuch x Arrays für die x Elemente in dem Bauteil und jeder dieser Arrays hat dann nochmal y arrays für die y Timesteps in der Simulation. Hab den Index deshalb einfach Elemente genannt. Mag sein, dass das jeder anders sieht oder man das generell in python anders handhabt. Für mich persönlich ist das aber immer gut nachvollziehbar. Ich weiß dann halt immer direkt worum es sich handelt.
__blackjack__ hat geschrieben: Sonntag 5. Mai 2019, 15:31 Ich denke die Nachteile sind offensichtlich – meine Funktion macht effektiv genau das was Deine macht. Ich habe da ja nichts anderes geschrieben, sondern nur den ganzen unnötigen Kram weg gelassen. Und da kommt weniger, klarerer Code bei heraus. Das ist vielleicht so ein bisschen die Frage was es für Nachteile hat bei einer Formel nicht gemeinsame Faktoren heraus zu ziehen, Brüche zu kürzen, und Konstanten zu verrechnen. Der Code ist das Ergebnis einer schrittweisen Vereinfachung.
Okay, ja das macht Sinn für mich. Vielen Dank.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei einer Datei mit Endung .txt würde ich eine Textdatei erwarten und keine Binärdatei.
Was soll denn die Umkopiererei mit dict_result?
Wie schon weiter oben geschrieben, ist pickle nur für den Datenaustausch gedacht und nicht dafür, Daten für längere Zeit zu speichern. Mit einer neuen Numpy-Version könnte es nämlich passieren, dass alte Pickle-Dateien plötzlich nicht mehr lesbar sind.

`print(os.path)` gibt Dir die Ausgabe eines Moduls, weil das ja nur ein Modul ist, was Du da ausgibst, statt dass Du eine Funktion in diesem Modul benutzt.

Ein Index ist nunmal nur ein Index und kein Element, um das klar zu machen, könntest Du auch element_index benutzen.
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

ThomasL hat geschrieben: Montag 6. Mai 2019, 15:21
Marvin93 hat geschrieben: Montag 6. Mai 2019, 15:09

Code: Alles auswählen

def save_dict_pickle(data):
    pickle_out = open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"wb")
    pickle.dump(data, pickle_out)
    pickle_out.close()
    
def load_dict_pickle():
    pickle_in = open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"rb")
    data = pickle.load(pickle_in)
    for key, value in data.items():
        dict_results[key] = value
Würde das für quasi unendlich große dictionaries und numpy arrays funktionieren?
Zuerst die Frage: pickle serialisiert und speichert ein Objekt im Speicher deines Rechners. Wenn du also unendlichen großen RAM hast, dann Ja, ansonsten Nein.
Okay das verstehe ich nicht so ganz. Ich schreibe das doch in eine Textdatei. Das Ganze muss doch in jedem Fall in dieses Format umgewandelt werden. Habe ich nicht das gleiche Problem, wenn ich das ins Binäre oder irgendein anderes Format umwandel?
Bekomme ich damit nicht sowieso erst Probleme, wenn es sich dann tatsächlich um Milliarden von zeichen.

ThomasL hat geschrieben: Montag 6. Mai 2019, 15:21 Dein Code wird mit dem "with" Kontextmanager noch eleganter.
Die Load Funktion ist fehlerhaft da dict_results undefiniert ist

Code: Alles auswählen

def save_dict_pickle(data):
    with open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"wb") as pickle_out:
        pickle.dump(data, pickle_out)
    
def load_dict_pickle():
    with open((filename.rsplit('.', 1)[0] + '__pickle.txt'),"rb") as pickle_in:
    data = pickle.load(pickle_in)
    return data
dict_results wird direkt am Anfang global erstellt. Das Dictionary wird quasi vom ganzen Programm verwendet. Ich öffne den code in einem Post-Prozessor und kann dann sämtliche Funktionen einfach nach belieben verwenden und will das nicht immer übergeben müssen. Ich habe das am Anfang noch anders probiert, hat aber nicht so geklappt wie ich wollte und ich hatte dann ehrlich gesagt keine Lust nach einer anderen Lösung zu suchen.
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

Sirius3 hat geschrieben: Montag 6. Mai 2019, 15:32 Bei einer Datei mit Endung .txt würde ich eine Textdatei erwarten und keine Binärdatei.
Was soll denn die Umkopiererei mit dict_result?
Wie schon weiter oben geschrieben, ist pickle nur für den Datenaustausch gedacht und nicht dafür, Daten für längere Zeit zu speichern. Mit einer neuen Numpy-Version könnte es nämlich passieren, dass alte Pickle-Dateien plötzlich nicht mehr lesbar sind.
Ja die Endung .txt ist falsch. dict_result wird im restlichen Programm verwendet und so muss ich die Daten nicht immer übergeben, sondern die anderen Funktionen können das Dictionary einfach direkt verwendent. Okay, dann muss ich doch noch eine andere Lösung finden. Mit HDF5 habe ich das Problem nicht?
Sirius3 hat geschrieben: Montag 6. Mai 2019, 15:32 `print(os.path)` gibt Dir die Ausgabe eines Moduls, weil das ja nur ein Modul ist, was Du da ausgibst, statt dass Du eine Funktion in diesem Modul benutzt.
Achso, okay jetzt versteh ich das. Danke
Sirius3 hat geschrieben: Montag 6. Mai 2019, 15:32 Ein Index ist nunmal nur ein Index und kein Element, um das klar zu machen, könntest Du auch element_index benutzen.
Okay, macht Sinn.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Marvin93 hat geschrieben: Montag 6. Mai 2019, 15:37 Okay das verstehe ich nicht so ganz. Ich schreibe das doch in eine Textdatei. Das Ganze muss doch in jedem Fall in dieses Format umgewandelt werden. Habe ich nicht das gleiche Problem, wenn ich das ins Binäre oder irgendein anderes Format umwandel?
Bekomme ich damit nicht sowieso erst Probleme, wenn es sich dann tatsächlich um Milliarden von zeichen.
Du kannst nur Daten speichern, die du in deinem Hauptspeicher/RAM hast, ist der unendlich ?
Marvin93 hat geschrieben: Montag 6. Mai 2019, 15:37 dict_results wird direkt am Anfang global erstellt. Das Dictionary wird quasi vom ganzen Programm verwendet. Ich öffne den code in einem Post-Prozessor und kann dann sämtliche Funktionen einfach nach belieben verwenden und will das nicht immer übergeben müssen. Ich habe das am Anfang noch anders probiert, hat aber nicht so geklappt wie ich wollte und ich hatte dann ehrlich gesagt keine Lust nach einer anderen Lösung zu suchen.
1) Vergiss dass es GLOBAL in Python gibt, Funktionen geben Daten per return zurück. Dazu sind Funktionen da.
Wenn das bei dir nicht geklappt hat, dann deshalb, weil du Fehler gemacht hast.
Innerhalb einer Funktion globale Daten zu verändern ist tödlich.
2) Vergiss dass es GLOBAL in Python gibt
3) siehe 1 und 2
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Marvin93
User
Beiträge: 38
Registriert: Samstag 4. Mai 2019, 15:16

ThomasL hat geschrieben: Montag 6. Mai 2019, 16:18
Marvin93 hat geschrieben: Montag 6. Mai 2019, 15:37 Okay das verstehe ich nicht so ganz. Ich schreibe das doch in eine Textdatei. Das Ganze muss doch in jedem Fall in dieses Format umgewandelt werden. Habe ich nicht das gleiche Problem, wenn ich das ins Binäre oder irgendein anderes Format umwandel?
Bekomme ich damit nicht sowieso erst Probleme, wenn es sich dann tatsächlich um Milliarden von zeichen.
Du kannst nur Daten speichern, die du in deinem Hauptspeicher/RAM hast, ist der unendlich ?
Nein aber, wenn das Dictionary zu groß für meinen RAM ist habe ich dann nicht sowieso ein Problem damit es zu verwenden?
ThomasL hat geschrieben: Montag 6. Mai 2019, 16:18
Marvin93 hat geschrieben: Montag 6. Mai 2019, 15:37 dict_results wird direkt am Anfang global erstellt. Das Dictionary wird quasi vom ganzen Programm verwendet. Ich öffne den code in einem Post-Prozessor und kann dann sämtliche Funktionen einfach nach belieben verwenden und will das nicht immer übergeben müssen. Ich habe das am Anfang noch anders probiert, hat aber nicht so geklappt wie ich wollte und ich hatte dann ehrlich gesagt keine Lust nach einer anderen Lösung zu suchen.
1) Vergiss dass es GLOBAL in Python gibt, Funktionen geben Daten per return zurück. Dazu sind Funktionen da.
Wenn das bei dir nicht geklappt hat, dann deshalb, weil du Fehler gemacht hast.
Innerhalb einer Funktion globale Daten zu verändern ist tödlich.
2) Vergiss dass es GLOBAL in Python gibt
3) siehe 1 und 2
Das funktioniert schon. Aber nicht so wie ich will. Wenn ich das Dictionary mit return zurückgebe muss ichs ja irgendwie in eine variable oder so schreiben und an jede neue Funktion übergeben. Ist mir einfach zu nervig. Verstehe ehrlich gesagt nicht wo das Problem liegt ein paar grundlegende Sachen die immer wieder benötigt werden Global zu definieren. Gerade ein Dictionary was von verschiedenen Funktionen erweitert werden kann/wird.
Benutzeravatar
__blackjack__
User
Beiträge: 13102
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marvin93: Du musst mit dem Pfad nichts machen was Du nicht auch machen würdest ohne den als Argument zu übergeben. Wenn der als Argument übergeben wird, heisst das ja nicht, das Du den als literal von Hand eintippen musst. Der kann an der Aufrufstelle auch aus anderen Pfaden ”berechnet” werden. Aber eben dort, weil es nicht in diese Funktion gehört und weil man nicht magisch auf irgendwelche Variablen aus der Umgebung zugreift. Die es auch gar nicht gibt, wenn man vernünftig programmiert.

Du brauchst für JSON den Speicher um die Daten *und* die als JSON serialisierten Daten *gleichzeitig* im Speicher zu halten, beziehungsweise auch noch etwas zusätzlichen Speicher der für die Umwandlung benötigt wird.

Das ist nicht grundsätzlich bei Daten-/Dateiformaten so. Es gibt auch welche die sich (besser) dafür eignen nicht komplett im Speicher vorliegen zu müssen um sie umwandeln zu können. Wenn man das in HDF5 speichert wird man beispielsweise die Schlüssel/Wert-Paare einzeln speichern/laden und die Arrays müssen auch nicht von oder in Text gewandelt werden.

Vergiss globale Variablen. Wenn Dir das zu ”nervig” ist sauber zu programmieren, dann lass es am besten ganz bleiben. Das ist ein Punkt in dem Du keinen Programmierer überzeugen könntest der nicht ganz gehörig einen an der Waffel hat. Das Problem ist, das Du damit undurchsichtige Abhängigkeiten zwischen Funktionen schaffst die es schwer machen Code zu verstehen, zu testen, Fehler zu finden, aber leicht Fehler zu machen, die dann schwer zu finden sind. Das scheint Dir kein grosses Problem zu sein – aber glaub mir, wenn es zu einem Problem wird, *dann* ist es ein grosses Problem, und ein nerviges, und dann muss man in der Regel um da irgendwie wieder heraus zu kommen, das ganze entwirren, was frustrierend ist, weil man dann das machen muss, was man gleich von Anfang an hätte machen sollen: keine globalen Variablen verwenden. Nur dass das beseitigen von globalen Variablen, wenn man nicht mehr durchsteigt, viel schwerer ist, als gar nicht erst damit anzufangen.

Ich frage mich auch ein bisschen ob Du mit dem Wörterbuch das gleiche Problem nicht noch einmal wiederholst und das eigentlich auch eine Sammlung von globalen Variablen sind die gar nicht wirklich zusammengehören, und Du nur zu faul warst die ordentlich zu strukturieren. Braucht wirklich jede Funktion alles was da drin ist? Falls nein, sollte man auch dieses Wörterbuch nicht einfach komplett überall herum reichen, denn das wäre vom Effekt auch nicht besser als das alles als globale Variablen zu definieren.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten