Ich war kürzlich überrascht zu entdecken, dass Diktate zwar die Einfügereihenfolge in Python 3.7+ beibehalten, Sets jedoch nicht:
>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> d
{'a': 1, 'b': 2, 'c': 3}
>>> d['d'] = 4
>>> d
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> s = {'a', 'b', 'c'}
>>> s
{'b', 'a', 'c'}
>>> s.add('d')
>>> s
{'d', 'b', 'a', 'c'}
Was ist der Grund für diesen Unterschied? Gilt die gleiche Effizienzverbesserung, die das Python-Team dazu veranlasst hat, die Diktatimplementierung zu ändern, nicht auch für Sets?
Ich suche nicht nach Hinweisen auf Implementierungen geordneter Mengen oder nach Möglichkeiten, Diktate als Ersatz für Mengen zu verwenden. Ich frage mich nur, warum das Python-Team nicht eingebaute Sets erstellt hat, um die Ordnung zu erhalten, während sie dies für Diktate getan haben.
dict
undset
seit 2.7 dieselbe Reihenfolge verwendet .Antworten:
Sets und Diktate sind für verschiedene Anwendungsfälle optimiert. Die Hauptverwendung eines Sets ist das schnelle Testen der Mitgliedschaft, was auftragsunabhängig ist.Für Diktate sind die Kosten für die Suche die kritischste Operation, und es ist wahrscheinlicher, dass der Schlüssel vorhanden ist. Bei Mengen ist das Vorhandensein oder Fehlen eines Elements nicht im Voraus bekannt, und daher muss die Mengenimplementierung sowohl für den gefundenen als auch für den nicht gefundenen Fall optimiert werden. Einige Optimierungen für allgemeine Mengenoperationen wie Vereinigung und Schnittmenge machen es außerdem schwierig, die Satzreihenfolge beizubehalten, ohne die Leistung zu beeinträchtigen.
Während beide Datenstrukturen auf Hash basieren, ist es ein weit verbreitetes Missverständnis, dass Mengen nur als Dikte mit Nullwerten implementiert werden. Bereits vor der kompakten Diktatimplementierung in CPython 3.6 unterschieden sich die Set- und Diktatimplementierungen erheblich, wobei nur wenig Code wiederverwendet wurde. Zum Beispiel verwenden Diktate eine randomisierte Prüfung, aber Sätze verwenden eine Kombination aus linearer Prüfung und offener Adressierung, um die Cache-Lokalität zu verbessern. Die anfängliche lineare Sonde (standardmäßig 9 Schritte in CPython) überprüft eine Reihe benachbarter Schlüssel / Hash-Paare und verbessert die Leistung, indem die Kosten für die Behandlung von Hash-Kollisionen gesenkt werden. Aufeinanderfolgender Speicherzugriff ist billiger als Streusonden.
dictobject.c
- master , v3.5.9setobject.c
- master , v3.5.9Theoretisch wäre es möglich , die Set-Implementierung von CPython so zu ändern, dass sie dem kompakten Diktat ähnelt. In der Praxis gibt es jedoch Nachteile, und namhafte Kernentwickler waren gegen eine solche Änderung.
- Guido van Rossum
- Raymond Hettinger
Eine ausführliche Diskussion darüber, ob Sets für 3.7 komprimiert werden sollen, und Antworten darauf, warum dagegen entschieden wurde, finden Sie in den Python-Dev-Mailinglisten.
Zusammenfassend sind die Hauptpunkte, dass die Verwendungsmuster unterschiedlich sind (Einfügungsreihenfolgen wie ** kwargs sind nützlich , weniger für Sets), die Platzersparnis für das Komprimieren von Sets ist weniger bedeutend (da nur Schlüssel- und Hash-Arrays vorhanden sind verdichten (im Gegensatz zu Schlüsseln, Hashes und Werten), und die oben erwähnte lineare Abtastoptimierung in Sätzen ist mit einer kompakten Implementierung nicht kompatibel.
Ich werde den Beitrag von Raymond unten wiedergeben, der die wichtigsten Punkte abdeckt.
Von [Python-Dev] Python 3.6 wird dict kompakt und erhält eine private Version; und Schlüsselwörter werden im September 2016 bestellt.
quelle
Diskussionen
Ihre Frage ist deutsch und wurde bereits vor kurzem intensiv über Python-Entwickler diskutiert . R. Hettinger teilte eine Liste von Begründungen in diesem Thread . Der Stand der Ausgabe erscheint jetzt, kurz nach dieser ausführlichen Antwort von T. Peters, offen .
Kurz gesagt, die Implementierung moderner Diktate, die die Einfügereihenfolge beibehalten, ist einzigartig und wird für Mengen nicht als angemessen angesehen. Insbesondere werden Dikte überall verwendet, um Python auszuführen (z. B.
__dict__
in Namespaces von Objekten). Eine Hauptmotivation für das moderne Diktat war die Reduzierung der Größe, wodurch Python insgesamt speichereffizienter wird. Im Gegensatz dazu sind Mengen in Pythons Kern weniger verbreitet als Diktate und raten daher von einem solchen Refactoring ab. Siehe auch R. Hettingers Vortrag über die Implementierung moderner Diktate.Perspektiven
Die Unordnung von Mengen in Python entspricht dem Verhalten mathematischer Mengen . Bestellung ist nicht garantiert.
Wenn in Python Mengen jeglicher Art eingeführt würden, würde dieses Verhalten einer völlig separaten mathematischen Struktur entsprechen, nämlich einer geordneten Menge (oder Oset). Osets spielen eine separate Rolle in der Mathematik, insbesondere in der Kombinatorik. Eine praktische Anwendung von Osets ist beobachtet Wechsel der Glocken .
Ungeordnete Mengen stehen im Einklang mit einer sehr allgemeinen und allgegenwärtigen Datenstruktur, die die modernste Mathematik, dh die Mengenlehre , aufhebt . Ich reiche ein, ungeordnete Sets in Python sind gut zu haben.
Siehe auch verwandte Beiträge, die dieses Thema erweitern:
quelle