Ich finde es bequemer, auf Diktierschlüssel zuzugreifen, als obj.foo
auf obj['foo']
, also habe ich diesen Ausschnitt geschrieben:
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
Ich gehe jedoch davon aus, dass es einen Grund geben muss, warum Python diese Funktionalität nicht sofort bereitstellt. Was wären die Vorbehalte und Gefahren beim Zugriff auf Diktatschlüssel auf diese Weise?
python
dictionary
syntax
attributes
Izz ad-Din Ruhulessin
quelle
quelle
collections.namedtuple
ist dafür sehr nützlich.easydict.EasyDict
Antworten:
Der beste Weg, dies zu tun, ist:
Einige Profis:
.keys()
. B. funktionieren sie einwandfrei. Es sei denn, Sie weisen ihnen einen Wert zu, siehe unten).AttributeError
stattKeyError
Nachteile:
.keys()
wird nicht gut funktionieren , wenn sie von eingehenden Daten überschriebenE1123(unexpected-keyword-arg)
undE1103(maybe-no-member)
Eine kurze Erklärung, wie das funktioniert
__dict__
.__dict__
"nur ein einfaches Diktat" sein muss, damit wirdict()
dem internen Wörterbuch eine beliebige Unterklasse zuweisen können .AttrDict()
Instanz zu, die wir instanziieren (wie wir uns gerade befinden__init__
).super()
der__init__()
Methode haben wir sichergestellt, dass sie sich (bereits) genau wie ein Wörterbuch verhält, da diese Funktion den gesamten Wörterbuch-Instanziierungscode aufruft .Ein Grund, warum Python diese Funktionalität nicht sofort bereitstellt
Wie in der Liste "Nachteile" angegeben, kombiniert dies den Namespace gespeicherter Schlüssel (die aus beliebigen und / oder nicht vertrauenswürdigen Daten stammen können!) Mit dem Namespace der eingebauten Diktatmethodenattribute. Zum Beispiel:
quelle
.
, können Sie die Regeln der Sprache nicht brechen :) Und ich möchte keineAttrDict
raumhaltigen Felder automatisch in etwas anderes konvertieren.Sie können alle zulässigen Zeichenfolgen als Teil des Schlüssels verwenden, wenn Sie die Array-Notation verwenden. Zum Beispiel,
obj['!#$%^&*()_']
quelle
What would be the caveats and pitfalls of accessing dict keys in this manner?
(als Attribute) und die Antwort ist, dass die meisten der hier gezeigten Zeichen nicht verwendbar wären.Aus dieser anderen SO-Frage geht ein großartiges Implementierungsbeispiel hervor, das Ihren vorhandenen Code vereinfacht. Wie wäre es mit:
Viel prägnanter und lässt keinen Raum für zusätzliche Kruft, die in Ihre
__getattr__
und__setattr__
Funktionen in der Zukunft gelangt .quelle
d = AttributeDict(foo=1)
.d.bar = 1
Das Balkenattribut wird im Diktatattribut gespeichert , jedoch nicht im Diktat selbst. Beim Druckend
wird nur das foo-Element angezeigt.d = AttributeDict(foo=1);d.bar = 1;print d
=>{'foo': 1, 'bar': 1}
Funktioniert für mich!__getattr__
Methode bereitstellen , die eineAttributeError
getattr(obj, attr, default_value)
default_value
attr
obj
Worin ich die gestellte Frage beantworte
Warum bietet Python es nicht sofort an?
Ich vermute, dass es mit dem Zen von Python zu tun hat : "Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun." Dies würde zwei offensichtliche Möglichkeiten für den Zugriff auf Werte aus Wörterbüchern schaffen:
obj['key']
undobj.key
.Vorsichtsmaßnahmen und Fallstricke
Dazu gehören mögliche Unklarheiten und Verwirrung im Code. dh könnte folgend jemand verwirrend sein sonst wer in wird Ihren Code zu einem späteren Zeitpunkt zu halten oder sogar zu Ihnen, wenn Sie nicht in es für eine Weile zurück. Nochmals aus dem Zen : "Lesbarkeit zählt!"
Wenn
d
instanziiert oderKEY
definiert oderd[KEY]
weit entfernt von wo zugewiesen wirdd.spam
Verwendungsort wird, kann dies leicht zu Verwirrung darüber führen, was getan wird, da dies keine häufig verwendete Redewendung ist. Ich weiß, es könnte mich verwirren.Wenn Sie den Wert von
KEY
wie folgt ändern (aber nicht ändernd.spam
), erhalten Sie jetzt außerdem:IMO, die Mühe nicht wert.
Andere Dinge
Wie andere angemerkt haben, können Sie jedes hashbare Objekt (nicht nur eine Zeichenfolge) als Diktatschlüssel verwenden. Zum Beispiel,
ist legal, aber
ist nicht. Auf diese Weise haben Sie Zugriff auf den gesamten Bereich druckbarer Zeichen oder anderer hashbarer Objekte für Ihre Wörterbuchschlüssel, über die Sie beim Zugriff auf ein Objektattribut nicht verfügen. Dies ermöglicht Magie wie eine zwischengespeicherte Objektmetaklasse, wie das Rezept aus dem Python-Kochbuch (Kap. 9) .
Worin ich redaktionell
Ich ziehe die Ästhetik
spam.eggs
überspam['eggs']
(ich glaube , es sauberer aussieht), und ich wirklich begonnen , diese Funktionalität Begierde , wenn ich das erfülltnamedtuple
. Aber die Bequemlichkeit, die folgenden Aufgaben ausführen zu können, übertrifft sie.Dies ist ein einfaches Beispiel, aber ich benutze häufig Diktate in anderen Situationen als ich
obj.key
Notation (dh wenn ich Einstellungen aus einer XML-Datei einlesen muss). In anderen Fällen, in denen ich aus ästhetischen Gründen versucht bin, eine dynamische Klasse zu instanziieren und einige Attribute darauf zu setzen, verwende ich weiterhin ein Diktat für die Konsistenz, um die Lesbarkeit zu verbessern.Ich bin sicher, dass das OP dies längst zu seiner Zufriedenheit gelöst hat, aber wenn er diese Funktionalität weiterhin möchte, dann schlage ich vor, dass er eines der Pakete von pypi herunterlädt, die es bereitstellen:
Bunch ist derjenige, mit dem ich besser vertraut bin. Unterklasse vondict
, damit Sie alle diese Funktionen haben.AttrDict sieht auch so aus, als wäre es auch ziemlich gut, aber ich bin nicht so vertraut damit und habe die Quelle nicht so detailliert durchgesehen wie Bunch .Um die Lesbarkeit seines Codes zu verbessern, empfehle ich jedoch dringend, seine Notationsstile nicht zu mischen. Wenn er diese Notation bevorzugt, sollte er einfach ein dynamisches Objekt instanziieren, seine gewünschten Attribute hinzufügen und es einen Tag nennen:
Wobei ich aktualisiere, um eine Folgefrage in den Kommentaren zu beantworten
In den Kommentaren (unten) fragt Elmo :
Obwohl ich diesen Anwendungsfall noch nie verwendet habe (
dict
aus Konsistenzgründen verwende ich eher verschachtelte ), funktioniert der folgende Code:quelle
Vorsichtsmaßnahme: Aus bestimmten Gründen scheinen Klassen wie diese das Multiprozessor-Paket zu brechen. Ich hatte nur eine Weile mit diesem Fehler zu kämpfen, bevor ich diese SO fand: Ausnahme in Python-Multiprocessing finden
quelle
Sie können eine praktische Containerklasse aus der Standardbibliothek abrufen:
um zu vermeiden, dass Codebits kopiert werden müssen. Kein Standardzugriff auf das Wörterbuch, aber es ist einfach, einen zurückzubekommen, wenn Sie es wirklich wollen. Der Code in argparse ist einfach,
quelle
types.SimpleNamespace
docs.python.org/dev/library/types.html#types.SimpleNamespaceWas wäre, wenn Sie einen Schlüssel wollten, der eine Methode wie
__eq__
oder war?__getattr__
?Und Sie könnten keinen Eintrag haben, der nicht mit einem Buchstaben beginnt
0343853
als Schlüssel nicht möglich.Und was ist, wenn Sie keinen String verwenden möchten?
quelle
pickle.dump
verwendet__getstate__
Tupel können Diktiertasten verwendet werden. Wie würden Sie in Ihrem Konstrukt auf Tupel zugreifen?
Auch namedtuple ist eine komfortable Struktur , die Werte über das Attribut Zugriff zur Verfügung stellen kann.
quelle
Wie wäre es mit Prodict , der kleinen Python-Klasse, die ich geschrieben habe , um sie alle zu regieren :)
Außerdem erhalten Sie eine automatische Code-Vervollständigung , rekursive Objektinstanziierungen und eine automatische Typkonvertierung !
Sie können genau das tun, wonach Sie gefragt haben:
Beispiel 1: Tipphinweis
Beispiel 2: Automatische Typkonvertierung
quelle
Es funktioniert im Allgemeinen nicht. Nicht alle gültigen Diktatschlüssel weisen adressierbare Attribute auf ("der Schlüssel"). Sie müssen also vorsichtig sein.
Python-Objekte sind im Grunde alle Wörterbücher. Ich bezweifle also, dass es viel Leistung oder andere Strafen gibt.
quelle
Dies geht nicht auf die ursprüngliche Frage ein, sollte aber für Leute nützlich sein, die wie ich hier landen, wenn sie nach einer Bibliothek suchen, die diese Funktionalität bietet.
Addict, es ist eine großartige Bibliothek dafür: https://github.com/mewwts/addict Es kümmert sich um viele Bedenken, die in früheren Antworten erwähnt wurden.
Ein Beispiel aus den Dokumenten:
Mit Süchtigen:
quelle
Ich habe mich gefragt, wie der aktuelle Status von "Diktatschlüsseln als attr" im Python-Ökosystem ist. Wie mehrere Kommentatoren hervorgehoben haben, ist dies wahrscheinlich nicht das, was Sie selbst von Grund auf neu rollen möchten , da es mehrere Fallstricke und Fußgewehre gibt, von denen einige sehr subtil sind. Auch würde ich nicht empfehlen, zu verwenden
Namespace
als Basisklasse Ich war auf diesem Weg, es ist nicht schön.Glücklicherweise gibt es mehrere Open Source-Pakete, die diese Funktionalität bieten und für die Pip-Installation bereit sind! Leider gibt es mehrere Pakete. Hier ist eine Zusammenfassung vom Dezember 2019.
Konkurrenten (letzter Commit für Master | #commits | #contribs | Coverage%):
Nicht mehr gewartet oder nicht mehr gewartet:
Ich empfehle derzeit munch oder süchtig . Sie haben die meisten Commits, Mitwirkenden und Releases und schlagen für jede eine gesunde Open-Source-Codebasis vor. Sie haben die sauberste readme.md, 100% Abdeckung und gut aussehende Tests.
Ich habe (vorerst!) Keinen Hund in diesem Rennen, außerdem habe ich meinen eigenen Diktat- / Attr-Code gewürfelt und eine Menge Zeit verschwendet, weil mir all diese Optionen nicht bekannt waren :). Ich könnte in Zukunft dazu beitragen, süchtig zu werden, da ich lieber ein solides Paket als ein paar fragmentierte sehen würde. Wenn Sie sie mögen, tragen Sie bei! Insbesondere sieht es so aus, als könnte Munch ein Codecov-Abzeichen und Addict ein Python-Versionsabzeichen verwenden.
Süchtige Profis:
süchtige Nachteile:
typing.Dict
wenn Siefrom addict import Dict
Munch-Profis:
munch Nachteile:
Worin ich redaktionell
Vor vielen Monden, als ich Texteditoren verwendete, um Python zu schreiben, mochte ich bei Projekten, die nur mit mir selbst oder einem anderen Entwickler durchgeführt wurden, den Stil von Diktatattrs und die Möglichkeit, Schlüssel durch einfaches Deklarieren einzufügen
foo.bar.spam = eggs
. Jetzt arbeite ich in Teams und verwende für alles eine IDE. Ich habe mich von diesen Arten von Datenstrukturen und der dynamischen Typisierung im Allgemeinen zu statischen Analysen, Funktionstechniken und Typhinweisen abgewandt. Ich habe angefangen, mit dieser Technik zu experimentieren und Pstruct mit Objekten meines eigenen Designs zu unterteilen:Auf diese Weise erhalten Sie ein Objekt, das sich immer noch wie ein Diktat verhält, aber Sie können auch viel starrer auf Schlüssel wie Attribute zugreifen. Der Vorteil hierbei ist, dass ich (oder die unglücklichen Konsumenten Ihres Codes) genau weiß, welche Felder existieren können und welche nicht, und die IDE kann Felder automatisch vervollständigen. Auch die Unterklassifizierung von Vanille
dict
bedeutet, dass die JSON-Serialisierung einfach ist. Ich denke, die nächste Entwicklung in dieser Idee wäre ein benutzerdefinierter Protobuf-Generator, der diese Schnittstellen emittiert, und ein netter Vorteil ist, dass Sie sprachübergreifende Datenstrukturen und IPC über gRPC nahezu kostenlos erhalten.Wenn Sie sich für attr-dicts entscheiden, ist es wichtig zu dokumentieren, welche Felder für Ihre eigene Gesundheit (und die Ihrer Teamkollegen) erwartet werden.
Fühlen Sie sich frei, diesen Beitrag zu bearbeiten / zu aktualisieren, um ihn aktuell zu halten!
quelle
addict
eines Attributs keine AusnahmenDict
ausgelöst werden, da ein neues Attribut zurückgegeben wird (dies ist erforderlich, damit foo.abc = 'bar' funktioniert).Hier ist ein kurzes Beispiel für unveränderliche Datensätze mit integrierten Funktionen
collections.namedtuple
:und ein Anwendungsbeispiel:
quelle
Um der Antwort etwas Abwechslung zu verleihen, hat sci-kit learn Folgendes implementiert
Bunch
:Alles, was Sie brauchen, ist, die Methoden
setattr
undgetattr
zu erhalten - diegetattr
Überprüfung auf Diktatschlüssel und die Überprüfung auf tatsächliche Attribute. Dassetstaet
ist ein Update für Update für Beizen / Unpickling „Bündel“ - wenn inerested Check https://github.com/scikit-learn/scikit-learn/issues/6196quelle
Sie müssen keine eigenen schreiben, da setattr () und getattr () bereits vorhanden sind.
Der Vorteil von Klassenobjekten kommt wahrscheinlich bei der Definition und Vererbung von Klassen zum Tragen.
quelle
Ich habe dies basierend auf den Eingaben aus diesem Thread erstellt. Ich muss allerdings odict verwenden, also musste ich get überschreiben und attr setzen. Ich denke, dies sollte für die meisten speziellen Anwendungen funktionieren.
Die Verwendung sieht folgendermaßen aus:
Die Klasse:
Dies ist ein ziemlich cooles Muster, das bereits im Thread erwähnt wurde. Wenn Sie jedoch nur ein Diktat erstellen und es in ein Objekt konvertieren möchten, das mit der automatischen Vervollständigung in einer IDE funktioniert, usw.:
quelle
Anscheinend gibt es jetzt eine Bibliothek dafür - https://pypi.python.org/pypi/attrdict - die genau diese Funktionalität plus rekursives Zusammenführen und Laden von JSON implementiert. Könnte einen Blick wert sein.
quelle
Das benutze ich
quelle
namedtuple('Args', list(args.keys()))(**args)
Sie können es mit dieser Klasse machen, die ich gerade gemacht habe. Mit dieser Klasse können Sie das
Map
Objekt wie ein anderes Wörterbuch (einschließlich JSON-Serialisierung) oder mit der Punktnotation verwenden. Ich hoffe dir zu helfen:Anwendungsbeispiele:
quelle
dict
Methoden beschatten kann, zB:m=Map(); m["keys"] = 42; m.keys()
gibtTypeError: 'int' object is not callable
.field/attribute
und keine zu seinmethod
, aber wenn Sie einer Methode stattdessen eine Nummer zuweisen, können Sie mit dieser Methode darauf zugreifenm.method()
.Lassen Sie mich eine weitere Implementierung veröffentlichen, die auf der Antwort von Kinvais aufbaut, aber Ideen aus dem in http://databio.org/posts/python_AttributeDict.html vorgeschlagenen AttributeDict integriert .
Der Vorteil dieser Version ist, dass sie auch für verschachtelte Wörterbücher funktioniert:
quelle
quelle
Lösung ist:
quelle
Wie @Henry vorschlägt, besteht ein Grund dafür, dass der Punktzugriff in Diktaten möglicherweise nicht verwendet wird, darin, dass Diktatschlüsselnamen auf Python-gültige Variablen beschränkt werden, wodurch alle möglichen Namen eingeschränkt werden.
Das Folgende sind Beispiele dafür, warum der Punktzugriff angesichts eines Diktats im Allgemeinen nicht hilfreich wäre
d
:Gültigkeit
Die folgenden Attribute wären in Python ungültig:
Stil
PEP8-Konventionen würden der Benennung von Attributen eine weiche Einschränkung auferlegen:
A. Reservierte Schlüsselwortnamen (oder integrierte Funktionsnamen):
B. Die Fallregel zu Methoden und Variablennamen :
Manchmal werden diese Bedenken in Bibliotheken wie Pandas geäußert , die den Punktzugriff auf DataFrame-Spalten nach Namen ermöglichen. Der Standardmechanismus zum Auflösen von Namensbeschränkungen ist auch die Array-Notation - eine Zeichenfolge in Klammern.
Wenn diese Einschränkungen für Ihren Anwendungsfall nicht gelten, gibt es verschiedene Optionen für Datenstrukturen mit gepunktetem Zugriff .
quelle
Sie können dict_to_obj https://pypi.org/project/dict-to-obj/ verwenden. Es macht genau das, wonach Sie gefragt haben
quelle
.idea
benutzerspezifische oder IDE-generierte Dateien in Ihre zu legen.gitignore
.Dies ist keine 'gute' Antwort, aber ich dachte, das wäre geschickt (es behandelt keine verschachtelten Diktate in der aktuellen Form). Wickeln Sie einfach Ihr Diktat in eine Funktion:
Jetzt haben Sie eine etwas andere Syntax. Zugriff auf die diktierten Elemente wie Attribute
f.key
. Um auf die Diktatelemente (und andere Diktiermethoden) wie gewohnt zuzugreifen, können Sie das Diktatf()['key']
bequem aktualisieren, indem Sie f mit Schlüsselwortargumenten und / oder einem Wörterbuch aufrufenBeispiel
Und da ist es. Ich würde mich freuen, wenn jemand Vor- und Nachteile dieser Methode vorschlägt.
quelle
Wie von Doug bemerkt, gibt es ein Bunch-Paket, mit dem Sie die
obj.key
Funktionalität erreichen können. Eigentlich gibt es eine neuere Version namensNeoBunch
Es hat jedoch eine großartige Funktion, mit der Sie Ihr Diktat über die Neobunchify- Funktion in ein NeoBunch-Objekt konvertieren können. Ich verwende häufig Mako-Vorlagen und die Übergabe von Daten als NeoBunch-Objekte macht sie weitaus lesbarer. Wenn Sie also zufällig ein normales Diktat in Ihrem Python-Programm verwenden, aber die Punktnotation in einer Mako-Vorlage möchten, können Sie sie folgendermaßen verwenden:
Und die Mako-Vorlage könnte folgendermaßen aussehen:
quelle
Der einfachste Weg ist, eine Klasse zu definieren. Nennen wir sie Namespace. welches das Objekt dict .update () auf dem dict verwendet. Dann wird das Diktat als Objekt behandelt.
quelle