Kann man sich auf dictionary Unordnung verlassen?

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.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

ich suche gerade nach einer geeigneten Struktur, um Attributnamen samt jeweiligem Werttyp zu hinterlegen. Jetzt weiß ich nicht, ob die dictionary Methoden 'keys' und 'values' immer die selbe Reihenfolge liefern:

Code: Alles auswählen

>>> APPT_ATTR
{'begin': 'datetime', 'end': 'datetime', 'longtext': 'str', 'title': 'str', 'owners': 'list', 'categories': 'list'}
>>> APPT_ATTR.keys()
['begin', 'end', 'longtext', 'title', 'owners', 'categories']
>>> APPT_ATTR.values()
['datetime', 'datetime', 'str', 'str', 'list', 'list']
Ansonsten würde ich die Namen und die Typen in 2 separate tuple stecken. Gefällt mir allerdings nicht, weil man da schon gut aufpassen muss, nichts durcheinander zu bringen... :)

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

mutetella hat geschrieben:Jetzt weiß ich nicht, ob die dictionary Methoden 'keys' und 'values' immer die selbe Reihenfolge liefern:

Code: Alles auswählen

>>> APPT_ATTR
{'begin': 'datetime', 'end': 'datetime', 'longtext': 'str', 'title': 'str', 'owners': 'list', 'categories': 'list'}
>>> APPT_ATTR.keys()
['begin', 'end', 'longtext', 'title', 'owners', 'categories']
>>> APPT_ATTR.values()
['datetime', 'datetime', 'str', 'str', 'list', 'list']
Im Zweifelsfall rufe die Informationen zusammen ab und zerlege sie dann.

Code: Alles auswählen

keys, values = zip(*APT_ATTR.items())
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@/me
Vielen Dank! Genau das Ergebnis versuche ich schon die ganze Zeit mit einer LC und 'items()' zu basteln. Ist nicht das erste mal, dass ich nicht an 'zip' denke. Das muss am Namen liegen, ich verbinde mit 'zip' einfach was anderes...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Deine Frage wird in der Dokumentation beantwortet: dict.items(). `zip(*d.items())` ist also nicht nötig.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@BlackJack
Ok... :oops: Um es mit lunars Worten auszudrücken: RTFM! :)

Was ich dabei allerdings nicht so wirklich verstehe:
items() hat geschrieben:... listed in an arbitrary order which is non-random, ...
Eine willkürliche Sortierung die nicht zufällig ist? Bezieht sich non-random darauf, dass es eben sehr wohl eine Sortierung gibt,
items() hat geschrieben:... depends on the dictionary’s history of insertions and deletions.
auf die aber nicht näher eingegangen wird und deshalb willkürlich erscheint?

Und zuletzt (auch wenn es sich somit erledigt hat):
Ließe sich /me's Lösung auch mit einer LC machen? Das lässt mir einfach keine Ruhe... :?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

BlackJack hat geschrieben:@mutetella: Deine Frage wird in der Dokumentation beantwortet: dict.items(). `zip(*d.items())` ist also nicht nötig.
Das liefert aber unterschiedliche Dinge. Ich war davon ausgegangen, dass zwei getrennte Listen/Tupel erstellt werden sollten.

d.items() lässt sich aber auch problemlos als zip(*zip(*d.items())) ausdrücken. :mrgreen:
BlackJack

@/me: Ich habe nicht gesagt er soll `dict.items()` verwenden, sondern das dort seine Frage beantwortet wird wie sich `dict.keys()` und `dict.values()` verhalten. Bei den beiden Methoden steht in der Doku der Hinweis auf die Bemerkung in der Doku zu `dict.items()`.

@mutetella: Die Ordnung ist nicht zufällig, aber es wird halt auch nicht so richtig verraten wonach sie sich richtet, weil das ein Implementierungsdetail ist. Konkret bei CPython ist ein `dict` als Hashtabelle implementiert.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

BlackJack hat geschrieben:@/me: Ich habe nicht gesagt er soll `dict.items()` verwenden, sondern das dort seine Frage beantwortet wird wie sich `dict.keys()` und `dict.values()` verhalten. Bei den beiden Methoden steht in der Doku der Hinweis auf die Bemerkung in der Doku zu `dict.items()`.
Mit dem Hinweis, dass das für CPython gilt. PyPy scheint sich allerdings ebenso zu verhalten - und es wäre auch merkwürdig wenn man es unterschiedlich implementieren würde -, aber eine Garantie für alle Plattformen und für alle folgenden Versionen hast du nicht.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

/me hat geschrieben:... aber eine Garantie für alle Plattformen und für alle folgenden Versionen hast du nicht.
Wobei der Grundsatz, dass 'keys()' und 'values()' jeweils eine Liste in derselben Reihenfolge zurückgeben, wird zwischen diversen Plattformen und Versionen ja wohl eingehalten werden, oder?
Andernfalls wäre Deine 'zip'-Lösung wohl das Sicherste...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

mutetella hat geschrieben:
/me hat geschrieben:Wobei der Grundsatz, dass 'keys()' und 'values()' jeweils eine Liste in derselben Reihenfolge zurückgeben, wird zwischen diversen Plattformen und Versionen ja wohl eingehalten werden, oder?
Und warum steht dann bei items() in Fettschrift: "CPython implementation detail"?

Wenn das in der Vergangenheit vielleicht seit langer Zeit immer und überall so war, dann kannst du natürlich durchaus glauben, dass sich das in Zukunft auch nicht ändert. Du bewegst dich dann allerdings nicht im Bereich der Informatik, sondern in dem der Religion. Immerhin könntest du dann darum beten, dass keiner die Implementierung ändern möge ...
BlackJack

@/me: Weil das was *in dem Kasten* steht ein CPython-Implementierungsdetail ist. Die Garantie um die es geht steht aber *nach* dem Kasten und gilt für alle Implementierungen.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dies hier ist der Schlüsselsatz:
If items(), keys(), values(), iteritems(), iterkeys(), and itervalues() are called with no intervening modifications to the dictionary, the lists will directly correspond.
Ein `dict`-Objekt - egal in welcher Python-Variante implementiert - muss also laut Sprachspezifikation garantieren, dass die Rückgabewerte der o.g. Methoden passend zueinander sind - sich also in ihrer Reihenfolge nicht verändern. Dies gilt solange, wie keine Veränderung am Wörterbuch vorgenommen wird. Ich denke, dies ist der Punkt, auf dem Blackjack aufmerksam machen wollte.

Zur Art der Reihenfolge wird halt nur gesagt, dass es in anderen Python-Implementationen durchaus eine andere Reihenfolge bei der Ausgabe geben kann, was aber nichts mit der außerhalb des Kastens genannten Garantie zu tun hat. Theoretisch wird nichtmal garantiert, dass zwei unterschiedliche `dict`-Instanzen mit der selben Änderungshistorie zwangsläufig die selbe Reihenfolge ausgeben müssten.

Man sollte sich also nicht auf die Reihenfolge im Detail verlassen, sondern nur darauf, dass sie sich wie gesagt nicht ändert, solange man nichts am Dictionary verändert.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

BlackJack hat geschrieben:@/me: Weil das was *in dem Kasten* steht ein CPython-Implementierungsdetail ist. Die Garantie um die es geht steht aber *nach* dem Kasten und gilt für alle Implementierungen.
Das stimmt natürlich. Ich hatte die Frage nach "diversen Plattformen und Versionen" so verstanden, dass ein identisches Verhalten über die Grenzen der aktuellen Python-Version erwartet wird. Innerhalb eines gegebenen Python-Biotops ist man definitiv auf der sicheren Seite.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Was soll ich machen? Es lässt mir keine Ruhe!!!

Ich versuche verzweifelt, folgendes in einer LC unterzubringen:

Code: Alles auswählen

>>> d = {'a': 'A', 'b': 'B'}
>>> result = [[], []]
>>> for key, value in d.items():
...     result[0].append(key)
...     result[1].append(value)
... 
>>> result
[['a', 'b'], ['A', 'B']]
Das einzige, das irgendwie in die Richtung geht war bisher das:

Code: Alles auswählen

>>> [[key for key, value in d.items()]]
[['a', 'b']]
Ich möchte jetzt gar nicht über Sinn oder Unsinn dieser LC reden... aber es muss doch irgendwie gehen...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Nö, das muss nicht gehen. Eine LC erstellt Elemente für eine Liste. Du möchtest aber zwei erstellen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

mutetella hat geschrieben: Ich möchte jetzt gar nicht über Sinn oder Unsinn dieser LC reden... aber es muss doch irgendwie gehen...
Wieso "muss" es das? ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Zwar keine LC aber auch kuerzer als eine:

Code: Alles auswählen

In [1]: d = {'a': 'A', 'b': 'B'}

In [2]: zip(*d.items())
Out[2]: [('a', 'b'), ('A', 'B')]
Ok, es sind Tupel ..
BlackJack

Nur noch mal damit es nicht in Vergessenheit gerät die eine offensichtliche Lösung:

Code: Alles auswählen

In [5]: d = {'a': 'A', 'b': 'B'}

In [6]: [d.keys(), d.values()]
Out[6]: [['a', 'b'], ['A', 'B']]
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

@Blackjack: sollte das Dictionary zwischen dem keys- und dem values-Aufruf verändert werden, bekommst Du Probleme:

Code: Alles auswählen

import time
import threading

d={'a': 'A', 'b': 'B'}

def add_c():
    time.sleep(.5)
    d['c']='C'
 
t=threading.Thread(target=add_c)
t.start();
print [d.keys(), time.sleep(1), d.values()]
# [['a', 'b'], None, ['A', 'C', 'B']]
@mutetella: Die offensichtliche Lösung, wie man LC nicht verwenden sollte:

Code: Alles auswählen

>>> d={'a': 'A', 'b': 'B'}
>>> keys=[]
>>> [keys,[keys.append(a) or b for a,b in d.iteritems()]]
[['a', 'b'], ['A', 'B']]
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

mutetella hat geschrieben:ich suche gerade nach einer geeigneten Struktur, um Attributnamen samt jeweiligem Werttyp zu hinterlegen. Jetzt weiß ich nicht, ob die dictionary Methoden 'keys' und 'values' immer die selbe Reihenfolge liefern:

Code: Alles auswählen

>>> APPT_ATTR
{'begin': 'datetime', 'end': 'datetime', 'longtext': 'str', 'title': 'str', 'owners': 'list', 'categories': 'list'}
>>> APPT_ATTR.keys()
['begin', 'end', 'longtext', 'title', 'owners', 'categories']
>>> APPT_ATTR.values()
['datetime', 'datetime', 'str', 'str', 'list', 'list']
Wieso nutzt du für die Werttypen eigentlich Strings? Geht doch eigentlch auch mit Klassen:

Code: Alles auswählen

{'begin': datetime, 'end': datetime, 'longtext': str, 'title': str, 'owners': list, 'categories': list}
Antworten