it-swarm.com.de

Sind Wörterbücher in Python 3.6+ sortiert?

Wörterbücher sind in Python 3.6 (zumindest unter der CPython-Implementierung) angeordnet, anders als in früheren Inkarnationen. Dies scheint eine wesentliche Änderung zu sein, aber es ist nur ein kurzer Absatz in der Dokumentation . Es wird eher als CPython-Implementierungsdetail als als Sprachfeature beschrieben, impliziert aber auch, dass dies in Zukunft zum Standard werden könnte.

Wie funktioniert die neue Wörterbuchimplementierung besser als die ältere, während die Elementreihenfolge beibehalten wird?

Hier ist der Text aus der Dokumentation:

dict() verwendet jetzt eine "kompakte" Darstellung Pionierarbeit von PyPy . Der Speicherverbrauch von new dict () ist zwischen 20% und 25% geringer als bei Python 3.5. PEP 468 (Beibehalten der Reihenfolge von ** kwargs in einer Funktion.) Wird dadurch implementiert. Der auftragserhaltende Aspekt dieser neuen Implementierung wird als Implementierungsdetail betrachtet und sollte nicht als vertrauenswürdig angesehen werden (dies kann sich in Zukunft ändern, es ist jedoch wünschenswert, diese neue diktierte Implementierung für einige Releases in der Sprache zu haben, bevor die Sprachspezifikation geändert wird Auftrag zur Beibehaltung der Reihenfolge für alle aktuellen und zukünftigen Python Implementierungen, dies hilft auch, die Abwärtskompatibilität mit älteren Versionen der Sprache zu erhalten, in denen die zufällige Iterationsreihenfolge noch gültig ist, zB Python 3.5). (Beitrag von INADA Naoki in Ausgabe 2735 . Idee rsprünglich vorgeschlagen von Raymond Hettinger .)

Update Dezember 2017: dicts Beibehaltung der Einfügereihenfolge ist garantiert für Python 3.7

355
Chris_Rands

Sind Wörterbücher in Python 3.6 + sortiert?

Sie sind Einfügung bestellt [1] . Ab Python 3.6 behalten Wörterbücher für die CPython-Implementierung von Python die Reihenfolge der eingefügten Elemente bei. Dies wird als Implementierungsdetail in Python 3.6 betrachtet. Sie müssen OrderedDict verwenden, wenn Sie eine Einfügungsreihenfolge wünschen, die für andere Implementierungen von Python (und für anderes geordnetes Verhalten) garantiert ist [1] ).

Ab Python 3.7 ist dies kein Implementierungsdetail mehr und wird stattdessen zu einem Sprachfeature. Aus einer Python-Dev-Nachricht von GvR :

Mach es so. "Dict behält die Reihenfolge der Einfügungen bei" lautet die Entscheidung. Vielen Dank!

Dies bedeutet einfach, dass Sie sich darauf verlassen können . Andere Implementierungen von Python müssen ebenfalls ein nach Einfügung geordnetes Wörterbuch anbieten, wenn sie eine konforme Implementierung von Python 3.7 sein sollen.


Wie funktioniert die Implementierung des Python 3.6-Wörterbuchs besser?[2] als die ältere unter Beibehaltung der Elementreihenfolge?

Im Wesentlichen durch Beibehalten von zwei Arrays .

  • Das erste Array, dk_entries , enthält die Einträge ( vom Typ PyDictKeyEntry ) für das Wörterbuch in der Reihenfolge, in der sie eingefügt wurden. Die Beibehaltung der Reihenfolge wird dadurch erreicht, dass es sich um ein Array handelt, bei dem neue Elemente immer am Ende eingefügt werden (Einfügereihenfolge).

  • Der zweite, dk_indices , enthält die Indizes für das Array dk_entries (dh Werte, die die Position des entsprechenden Eintrags in dk_entries angeben). Dieses Array fungiert als Hash-Tabelle. Wenn ein Schlüssel gehasht wird, führt dies zu einem der in dk_indices gespeicherten Indizes, und der entsprechende Eintrag wird durch Indizieren von dk_entries abgerufen. Da nur Indizes beibehalten werden, hängt der Typ dieses Arrays von der Gesamtgröße des Wörterbuchs ab (von Typ int8_t (1 byte) bis int32_t / int64_t (4/8 bytes) auf 32/64 bit builds)

In der vorherigen Implementierung musste ein spärliches Array vom Typ PyDictKeyEntry und der Größe dk_size zugewiesen werden. Leider führte dies auch zu viel freiem Speicherplatz, da dieses Array nicht mehr als 2/3 * dk_size full aus Leistungsgründen sein durfte. (und der leere Raum hatte noch PyDictKeyEntry Größe!).

Dies ist jetzt nicht der Fall, da nur die erforderlichen Einträge gespeichert werden (diejenigen, die eingefügt wurden) und ein spärliches Array vom Typ intX_t (X abhängig von der Diktatgröße). 2/3 * dk_sizes full bleibt erhalten. Das Leerzeichen wurde von Typ PyDictKeyEntry in intX_t geändert.

Daher ist das Erstellen eines spärlichen Arrays vom Typ PyDictKeyEntry viel speicherintensiver als ein spärliches Array zum Speichern von ints.

Sie können die vollständige Konversation auf Python-Dev zu dieser Funktion sehen. Wenn Sie interessiert sind, ist dies eine gute Lektüre.


In dem ursprünglichen Vorschlag von Raymond Hettinger ist eine Visualisierung der verwendeten Datenstrukturen zu sehen, die den Kern der Idee erfasst.

Zum Beispiel das Wörterbuch:

d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}

ist derzeit gespeichert als:

entries = [['--', '--', '--'],
           [-8522787127447073495, 'barry', 'green'],
           ['--', '--', '--'],
           ['--', '--', '--'],
           ['--', '--', '--'],
           [-9092791511155847987, 'timmy', 'red'],
           ['--', '--', '--'],
           [-6480567542315338377, 'guido', 'blue']]

Stattdessen sollten die Daten wie folgt organisiert werden:

indices =  [None, 1, None, None, None, 0, None, 2]
entries =  [[-9092791511155847987, 'timmy', 'red'],
            [-8522787127447073495, 'barry', 'green'],
            [-6480567542315338377, 'guido', 'blue']]

Wie Sie jetzt visuell sehen können, ist im ursprünglichen Vorschlag viel Platz im Wesentlichen leer, um Kollisionen zu reduzieren und das Nachschlagen zu beschleunigen. Mit dem neuen Ansatz reduzieren Sie den Speicherbedarf, indem Sie die Spärlichkeit in die Indizes verschieben, in denen sie wirklich benötigt wird.


[1]: Ich sage "Einfügung bestellt" und nicht "bestellt", da "bestellt" mit der Existenz von OrderedDict ein weiteres Verhalten vorschlägt, das das dict -Objekt nicht bietet . OrderedDicts sind reversibel, bieten auftragssensitive Methoden und bieten hauptsächlich auftragssensitive Gleichheitstests (==, !=). dicts bieten derzeit keine dieser Verhaltensweisen/Methoden an.


[2]: Die neuen Wörterbuchimplementierungen erzielen eine bessere Speicherleistung , indem sie kompakter gestaltet werden. Das ist der Hauptvorteil hier. In Bezug auf die Geschwindigkeit ist der Unterschied nicht so drastisch. Es gibt Stellen, an denen das neue Dikt leichte Regressionen hervorrufen könnte ( zum Beispiel Tastensuche ), während in anderen Fällen (Iteration und Größenänderung in den Sinn kommen) eine Leistungssteigerung in Betracht gezogen werden sollte anwesend sein.

Insgesamt verbessert sich die Leistung des Wörterbuchs, insbesondere in realen Situationen, aufgrund der eingeführten Kompaktheit.

387

Im Folgenden wird die ursprüngliche erste Frage beantwortet:

Soll ich dict oder OrderedDict in Python 3.6 verwenden?

Ich denke, dieser Satz aus der Dokumentation reicht tatsächlich aus, um Ihre Frage zu beantworten

Der auftragserhaltende Aspekt dieser neuen Implementierung wird als Implementierungsdetail betrachtet und sollte nicht als verlässlich angesehen werden

dict ist nicht ausdrücklich als geordnete Sammlung gedacht. Wenn Sie also konsistent bleiben und sich nicht auf einen Nebeneffekt der neuen Implementierung verlassen möchten, sollten Sie bei OrderedDict bleiben.

Machen Sie Ihren Code zukunftssicher :)

Es gibt eine Debatte darüber hier .

BEARBEITEN: Python 3.7 behält dieses Feature bei siehe

62
Maresh

Update: Guido van Rossum angekündigt auf der Mailingliste dass ab Python 3.7 dicts in allen Python Implementierungen die Einfügereihenfolge beibehalten müssen.

19
fjsj

Ich wollte der obigen Diskussion etwas hinzufügen, habe aber nicht den Ruf, Kommentare abzugeben.

Python 3.8 ist noch nicht ganz freigegeben, wird aber sogar die Funktion reversed() für Wörterbücher enthalten (um einen weiteren Unterschied zu OrderedDict zu beseitigen).

Dict und Dictviews können jetzt in umgekehrter Reihenfolge mit reverse () iteriert werden. (Beigetragen von Rémi Lapeyre in bpo-33462.) Sehen Sie, was in python 3.8 neu ist

Ich sehe keine Erwähnung des Gleichheitsoperators oder anderer Merkmale von OrderedDict, so dass sie immer noch nicht ganz gleich sind.

1
rkengler