Halli hallo,
ich habe ein dictionary in eine textfile geschrieben und mittels der
Klasse Abstract Syntax Tree über ast.literal_eval() wieder von einem
string in eine dictionary verwandelt.
Funktioniert in der Praxis, mit einer nicht unbedeutenden Einschränkung.
Jedes Mal, wenn das Programm läuft, wird das neu eingelesene dictionary
in einer anderen Reihenfolge ausgegeben, was eher suboptimal ist. Weiß
jemand warum?
Ich nehme mal an, dass es um Python geht ..
Python dictionaries garantieren von Natur aus keine Reihenfolge der
Elemente. Wenn Du das brauchst, kannst Du collections.OrderedDict
verwenden.
Ich weiss aber nicht, wie man das mit deinem ast.literal_eval()
zusammenbringt.
Vielleicht kannst Du das dictionary auch in anderer Form speichern. Z.B.
als JSON oder YAML und kommst damit weiter.
Der frühen Stunde geschuldet habe ich vergessen, dass es sich
tatsächlich um Python3 handelt.
Also wenn ich das richtig sehe, bezieht sich das mit den collections auf
die zeitliche Reihenfolge der Keys in Bezug auf deren Erstellung.
"An OrderedDict is a dict that remembers the order that keys were first
inserted"
Was mich ganz praktisch interessiert sind aber die Values und hier der
absolute (int) Wert.
Das Ganze wird daher auch mit einer dict-comprehension neu abgebildet,
um das zu bezwecken. Hierbei viel mir dann aber besagter Sachverhalt
auf, dass schon das abzubildende Dict jedes Mal anders aussah.
In den Docs steht "It is best to think of a dictionary as an unordered
set of key: value pairs", heisst doch im Endeffekt, egal ob ich das über
ast einlese oder direkt ein dict habe, die Reihenfolge ist immer shuffle
oder wie?? Merkwürdig, sehr merkwürdig.
> die Reihenfolge ist immer shuffle oder wie?? Merkwürdig, sehr merkwürdig.
Ohne jetzt die konkreten Details von Python zu kennen, kann ich sagen,
dass das nichts Ungewöhnliches ist. Unordered Dictionaries werden meist
durch Hashtables implementiert. Zum einen wird als Hashwert gerne die
Adresse des Keys benutzt, die von Programmlauf zu Programmlauf
unterschiedlich sein kann (Stichwort ASLR). Im weiteren wird gerne ein
zusätzlicher Zufallswert mit in den Hash reingerechnet um
Hashkollisionsangriffe zu vermeiden. Beides führt dazu, dass ein und
der selbe Key immer in unterschiedlichen Slots des Hashtables landet.
Ein anschließendes Iterieren über den Hash liefert dann eine nicht
vorhersagbare Reihenfolge der Einträge. Diese ist nicht mal stabil -
ein Rehashing (z.B. ein Element hinzufügen und gleich wieder löschen)
kann zu einer total anderen Reihenfolge der exakt gleichen Elemente
führen.
Danke für die Erklärung(en) und die Arbeit, die mir das ganz sicher
erspart.
Im ersten Abschnitt der offizielen Docs steht auch "... returns an
arbitrary order..."
Nur wäre ich ehrlich gesagt nicht auf die Idee gekommen, weshalb man das
so handhabt, aber nun gut.
Wenn man eine bestehende dictionary einliest und dann in gutem Glauben
das Folgende macht, wenn die range bspw. 200 ist, dann Helm ab zum
Gebet.
Waldemarie schrieb:> Also wenn ich das richtig sehe, bezieht sich das mit den collections auf> die zeitliche Reihenfolge der Keys in Bezug auf deren Erstellung.
Genau. Und auch wenn du die Elemente mit einem Iterable initialisierst,
bleiben die Elemente in der vorgegebenen Reihenfolge. Eigentlich hätte
ich gedacht, dass ein OrderedDict genau das ist, was dein Problem löst.
> Was mich ganz praktisch interessiert sind aber die Values und hier der> absolute (int) Wert.
Diesen Satz habe ich nicht verstanden. Ist er als Begründung gedacht,
warum du kein OrderedDict verwenden möchtest?
Ab Python 3.6 sind übrigens auch die normalen Dictionaries "insertion-
ordered", und es ist offiziell entschieden worden, diese Eigenschaft in
die Sprachspezifikation aufzunehmen, d.h. sie ist auch für zukünftige
Python-Versionen garantiert. Du solltest dieses Feature aber nur nutzen,
wenn dein Code nicht auf älteren Versionen lauffähig sein muss. Also
wohl besser nicht, da du offensichtlich selber noch eine ältere Version
benutzt.
Waldemarie schrieb:> Wenn man eine bestehende dictionary einliest und dann in gutem Glauben> das Folgende macht, wenn die range bspw. 200 ist, dann Helm ab zum> Gebet.> {x: 9 for x in range(100)}>> popkornfaktor garantiert.
Auch das habe ich nicht verstanden. Vielleicht bin ich auch einfach noch
nicht ganz wach :)
Sven B. schrieb:> Die Verwendung des ast-Moduls hier ist fraglich. Warum machst du das so?> Ein JSON-Parser wäre die normale Lösung.
Das führt zum selben Problem, nur über Umwege.
Auch JSON-Objekte sind ungeordnet. Der JSON-Decoder (zumindest der aus
der Python-Standardbibliothek) erzeugt daraus ein ebenfalls ungeordnetes
Dictionary, so dass am Ende überhaupt nichts gewonnen ist.
Yalu X. schrieb:> Sven B. schrieb:>> Die Verwendung des ast-Moduls hier ist fraglich. Warum machst du das so?>> Ein JSON-Parser wäre die normale Lösung.>> Das führt zum selben Problem, nur über Umwege.>> Auch JSON-Objekte sind ungeordnet. Der JSON-Decoder (zumindest der aus> der Python-Standardbibliothek) erzeugt daraus ein ebenfalls ungeordnetes> Dictionary, so dass am Ende überhaupt nichts gewonnen ist.
Ja, natürlich. Das ist ein davon unabhängiges Problem.
Seit Python 3.7 sind dictionaries offiziell geordnet. Inoffiziell schon
seit 3.6 (implementation detail).
Die Reihenfolge entspricht der Erstellung eines Keys (insertion order).
Wenn Writer und Reader (JSON, CSV, usw) diese Reihenfolge nicht selbst
verändern, dann kommt am Ende dasselbe raus.
So oder so gibt es keinen vernünftigen Grund, sich was mit mit dem
ast-Modul selber zu klöppeln.
Edit: Kann keine entsprechende Python Version garantiert werden, ist
natürlich OrderedDict das Mittel der Wahl. Auch in diesem Fall sollte
man sich die Dokumentation von Writer/Reader diesbezüglich genau
ansehen.