Was sind Wörterbuchansichtsobjekte?

In Python 2.7 haben wir die Dictionary-View-Methoden verfügbar gemacht.

Jetzt kenne ich die Vor- und Nachteile des Folgenden:

  • dict.items() (und values , keys ): gibt eine Liste zurück, so dass Sie das Ergebnis speichern können und
  • dict.iteritems() (und dergleichen): gibt einen Generator zurück, so dass Sie jeden einzelnen erzeugten Wert nacheinander dict.iteritems() können.

Was sind dict.viewitems() (und ähnliches) für? Was sind ihre Vorteile? Wie funktioniert es? Was ist eine Aussicht?

Ich habe gelesen, dass die Ansicht immer die Änderungen aus dem Wörterbuch widerspiegelt. Aber wie verhält es sich im Hinblick auf Perfusion und Speicher? Was sind die Vor- und Nachteile?

   

Dictionary-Ansichten sind im Wesentlichen, was ihr Name sagt: Ansichten sind einfach wie ein Fenster auf die Schlüssel und Werte (oder Elemente) eines Wörterbuchs. Hier ein Auszug aus der offiziellen Dokumentation zu Python 3:

 >>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500} >>> keys = dishes.keys() >>> values = dishes.values() >>> # view objects are dynamic and reflect dict changes >>> del dishes['eggs'] >>> keys # No eggs anymore! dict_keys(['sausage', 'bacon', 'spam']) >>> values # No eggs value (2) anymore! dict_values([1, 1, 500]) 

(Das Python 2-Äquivalent verwendet die dishes.viewkeys() und ” dishes.viewvalues() .)

Dieses Beispiel zeigt den dynamischen Charakter von Ansichten : Die Schlüsselansicht ist keine Kopie der Schlüssel zu einem bestimmten Zeitpunkt, sondern ein einfaches Fenster, das Ihnen die Schlüssel zeigt; Wenn sie geändert werden, ändert sich auch, was Sie durch das Fenster sehen. Diese function kann unter bestimmten Umständen nützlich sein (z. B. kann man mit einer Ansicht auf die Schlüssel in mehreren Teilen eines Programms arbeiten, anstatt die aktuelle Liste der Schlüssel jedes Mal neu zu berechnen). Beachten Sie, dass die Wörterbuchschlüssel geändert werden Beim Iterieren über die Ansicht ist nicht klar definiert, wie sich der Iterator verhalten soll, was zu Fehlern führen kann .

Ein Vorteil ist, dass, wenn man sich anschaut, die Schlüssel nur eine kleine und feste Menge an Speicher verwenden und eine kleine und feste Menge an processorzeit benötigen, da es keine Liste von Schlüsseln gibt (Python 2, auf der anderen Seite, erstellt oft unnötigerweise eine neue Liste, wie von Rajendran T zitiert, die Speicher und Zeit in einer Menge proportional zur Länge der Liste nimmt). Um die Fensteranalogie fortzusetzen, wenn Sie eine Landschaft hinter einer Wand sehen wollen, machen Sie einfach eine Öffnung darin (Sie bauen ein Fenster); Wenn du die Schlüssel in eine Liste kopierst, würdest du stattdessen eine Kopie der Landschaft auf deiner Wand malen – die Kopie braucht Zeit, Platz und aktualisiert sich nicht.

Zusammengefasst sind Ansichten einfach … Ansichten (Fenster) in Ihrem Wörterbuch, die den Inhalt des Wörterbuchs anzeigen, selbst nachdem es sich geändert hat. Sie bieten functionen, die sich von denen der Listen unterscheiden: Eine Liste von Schlüsseln enthält eine Kopie der Wörterbuchschlüssel zu einem bestimmten Zeitpunkt, während eine Ansicht dynamisch ist und viel schneller zu erhalten ist, da sie keine Daten kopieren muss ( Schlüssel oder Werte), um erstellt zu werden.

Wie Sie bereits erwähnt haben, gibt dict.items() eine Kopie der Liste der Wörter (Schlüssel, Wert) zurück, die verschwenderisch ist, und dict.iteritems() gibt einen Iterator über die Paare (Schlüssel, Wert) des Wörterbuchs zurück.

Betrachten Sie nun das folgende Beispiel, um den Unterschied zwischen einem Interpreter von dict und einer Ansicht von dict zu sehen

 >>> d = {"x":5, "y":3} >>> iter = d.iteritems() >>> del d["x"] >>> for i in iter: print i ... Traceback (most recent call last): File "", line 1, in  RuntimeError: dictionary changed size during iteration 

Während eine Ansicht einfach zeigt, was im Diktat ist. Es ist egal, ob es sich geändert hat:

 >>> d = {"x":5, "y":3} >>> v = d.viewitems() >>> v dict_items([('y', 3), ('x', 5)]) >>> del d["x"] >>> v dict_items([('y', 3)]) 

Eine Ansicht ist einfach so, wie das Wörterbuch jetzt aussieht. Nach dem Löschen eines Eintrags wäre .items() nicht mehr aktuell und .iteritems() hätte einen Fehler ausgetriggers.

Schon beim Lesen der Dokumente habe ich den Eindruck:

  1. Ansichten sind “pseudo-set-like”, da sie die Indizierung nicht unterstützen. Sie können also mit ihnen die Mitgliedschaft testen und über sie iterieren (da die Schlüssel hashbar und eindeutig sind, sind die Schlüssel und Elemente mehr ” satzähnlich “darin, dass sie keine Duplikate enthalten).
  2. Sie können sie speichern und wie die Listenversionen mehrfach verwenden.
  3. Da sie das zugrunde liegende Wörterbuch widerspiegeln, wird jede Änderung im Wörterbuch die Ansicht ändern und höchstwahrscheinlich die Reihenfolge der Iteration ändern . Im Gegensatz zu den Listenversionen sind sie nicht “stabil”.
  4. Da sie das zugrunde liegende Wörterbuch widerspiegeln, handelt es sich mit ziemlicher Sicherheit um kleine Proxy-Objekte. Das Kopieren der Schlüssel / Werte / Elemente würde erfordern, dass sie das ursprüngliche Wörterbuch irgendwie betrachten und es mehrfach kopieren, wenn Änderungen passieren, was eine absurde Implementierung wäre. So würde ich sehr wenig Speicheraufwand erwarten, aber Zugriff auf etwas langsamer als direkt auf das Wörterbuch.

Ich denke also, der Schlüsselfall ist, wenn Sie ein Wörterbuch herumführen und wiederholt über seine Schlüssel / Elemente / Werte mit Änderungen dazwischen iterieren. Sie könnten stattdessen einfach eine Ansicht verwenden, indem Sie for k, v in mydict.iteritems(): in for k, v in myview: Aber wenn Sie nur einmal über das Wörterbuch iterieren, denke ich, dass die Iter-Versionen immer noch vorzuziehen sind.

Die Ansichtsmethoden geben eine Liste zurück (keine Kopie der Liste im Vergleich zu .keys() , .items() und .values() ), sodass sie leichter ist, aber den aktuellen Inhalt des Wörterbuchs widerspiegelt.

Ab Python 3.0 – dict-Methoden geben Views zurück – warum?

Der Hauptgrund ist, dass für viele Anwendungsfälle die Rückgabe einer vollständig getrennten Liste unnötig und verschwenderisch ist. Es würde erfordern, den gesamten Inhalt zu kopieren (was möglicherweise oder viel nicht viel ist).

Wenn Sie einfach über die Schlüssel iterieren möchten, ist das Erstellen einer neuen Liste nicht erforderlich. Und wenn Sie es tatsächlich als separate Liste benötigen (als Kopie), können Sie diese Liste einfach aus der Ansicht erstellen.

Mit Ansichten können Sie auf die darunterliegende Datenstruktur zugreifen, ohne sie zu kopieren. Abgesehen davon, dass sie im Gegensatz zur Erstellung einer Liste dynamisch ist, ist eine ihrer nützlichsten Anwendungen in Test. Angenommen, Sie möchten prüfen, ob ein Wert im Diktat enthalten ist (entweder Schlüssel oder Wert).

Die dict.keys() besteht darin, mit dict.keys() eine Liste der Schlüssel zu erstellen. Dies funktioniert, verbraucht aber offensichtlich mehr Speicher. Wenn das Diktat sehr groß ist? Das wäre verschwenderisch.

Mit views Sie die eigentliche Datenstruktur ohne Zwischenliste iterieren.

Lassen Sie uns Beispiele verwenden. Ich habe ein Diktat mit 1000 Tasten mit zufälligen Zeichenfolgen und Ziffern und k ist der Schlüssel, nach dem ich suchen möchte

 large_d = { .. 'NBBDC': '0RMLH', 'E01AS': 'UAZIQ', 'G0SSL': '6117Y', 'LYBZ7': 'VC8JQ' .. } >>> len(large_d) 1000 # this is one option; It creates the keys() list every time, it's here just for the example timeit.timeit('k in large_d.keys()', setup='from __main__ import large_d, k', number=1000000) 13.748743600954867 # now let's create the list first; only then check for containment >>> list_keys = large_d.keys() >>> timeit.timeit('k in list_keys', setup='from __main__ import large_d, k, list_keys', number=1000000) 8.874809793833492 # this saves us ~5 seconds. Great! # let's try the views now >>> timeit.timeit('k in large_d.viewkeys()', setup='from __main__ import large_d, k', number=1000000) 0.08828549011070663 # How about saving another 8.5 seconds? 

Wie Sie sehen, steigert das iterierende view Objekt die performance enorm und reduziert gleichzeitig den Speicheraufwand. Sie sollten sie verwenden, wenn Sie ähnliche Operationen ausführen müssen.

Hinweis : Ich verwende Python 2.7