Ich suche nach einer eleganten Möglichkeit, Daten mithilfe des Attributzugriffs auf ein Diktat mit einigen verschachtelten Diktaten und Listen abzurufen (dh Objektsyntax im Javascript-Stil).
Zum Beispiel:
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
Sollte auf diese Weise zugänglich sein:
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar
Ich denke, dies ist ohne Rekursion nicht möglich, aber was wäre ein guter Weg, um einen Objektstil für Diktate zu erhalten?
python
object
dictionary
Marc
quelle
quelle
from_
eher als_from
nach PEP 8 .getattr(x, 'from')
das Attribut verwenden, anstatt es umzubenennen.d1.b.c
). Ich denke, es ist klar, dass Sie etwas aus einer Bibliothek verwenden sollten, z. B. ein benanntes Tupel aus Sammlungen , wie diese Antwort nahelegt. .Antworten:
Update: Überlegen Sie in Python 2.6 und höher, ob die
namedtuple
Datenstruktur Ihren Anforderungen entspricht:Die Alternative (ursprünglicher Antwortinhalt) ist:
Dann können Sie verwenden:
quelle
Struct
s aus verschachtelten Wörterbüchern erstellt, aber im Allgemeinen kann der Werttyp beliebig sein. Der Schlüssel ist darauf beschränkt, für einen Objektschlitz geeignet zu seinargparse.Namespace
(die auch definiert hat__eq__
,__ne__
,__contains__
).quelle
if isinstance(b, (list, tuple)):
obj
Klasseargparse.Namespace
für zusätzliche Funktionen wie die lesbare Zeichenfolgendarstellung erben .Überraschenderweise hat niemand Bunch erwähnt . Diese Bibliothek soll ausschließlich den Zugriff auf Attributstile auf diktierte Objekte ermöglichen und genau das tun, was das OP wünscht. Eine Demonstration:
Eine Python 3-Bibliothek finden Sie unter https://github.com/Infinidat/munch - Das Guthaben geht an codyzu
quelle
Fügen Sie dann eine Rekursion hinzu und Sie sind fertig.
Bearbeiten Sie dies so, wie ich es implementieren würde:
quelle
top_instance = top()
und das zurückgeben, wo Sie zurückkehrentop
?x
x.b
<class '__main__.new'>
Es gibt einen Sammlungshelfer namens
namedtuple
, der dies für Sie tun kann:quelle
Kann mit jeder Sequenz / Diktat / Wertestruktur beliebiger Tiefe verwendet werden.
quelle
def __repr__(self): return '{%s}' % str(', '.join("'%s': %s" % (k, repr(v)) for (k, v) in self.__dict__.iteritems()))
.items()
statt.iteritems()
in Zeile 4. (Die Funktion wurde umbenannt, tut aber im Wesentlichen das gleiche )Ich nehme an, was die besten Aspekte der vorherigen Beispiele sind, und habe mir Folgendes ausgedacht:
quelle
def __init__(self, dct): for k, v in dct.iteritems(): setattr(self, k, isinstance(v, dict) and self.__class__(v) or v)
wodurch auch der explizite Aufruf vonStruct
isinstance(v, dict)
Scheck wäre besser, daisinstance(v, collections.Mapping)
er zukünftige diktähnliche Dinge handhaben kannWenn Ihr Diktat stammt
json.loads()
, können Sie es stattdessen in einer Zeile in ein Objekt (anstatt in ein Diktat) verwandeln:Siehe auch So konvertieren Sie JSON-Daten in ein Python-Objekt .
quelle
.loads
wenn Sie ein riesiges JSON-Objekt habenWenn Sie als Objekt (oder als Diktat für schwierige Schlüssel) auf Diktatschlüssel zugreifen möchten, tun Sie dies rekursiv und können Sie auch das ursprüngliche Diktat aktualisieren. Sie können Folgendes tun:
Anwendungsbeispiel:
quelle
quelle
Am Ende habe ich BEIDE AttrDict ausprobiert als auch das BunchBibliotheken und fand sie viel zu langsam für meine Zwecke. Nachdem ein Freund und ich uns damit befasst hatten, stellten wir fest, dass die Hauptmethode zum Schreiben dieser Bibliotheken dazu führt, dass die Bibliothek aggressiv durch ein verschachteltes Objekt rekursiert und durchgehend Kopien des Wörterbuchobjekts erstellt. Vor diesem Hintergrund haben wir zwei wichtige Änderungen vorgenommen. 1) Wir haben Attribute faul geladen. 2) Anstatt Kopien eines Wörterbuchobjekts zu erstellen, erstellen wir Kopien eines leichten Proxy-Objekts. Dies ist die endgültige Implementierung. Die Leistungssteigerung bei der Verwendung dieses Codes ist unglaublich. Bei Verwendung von AttrDict oder Bunch haben diese beiden Bibliotheken allein 1/2 bzw. 1/3 meiner Anforderungszeit beansprucht (was!?). Dieser Code reduzierte diese Zeit auf fast nichts (irgendwo im Bereich von 0,5 ms). Dies hängt natürlich von Ihren Bedürfnissen ab,
Die ursprüngliche Implementierung finden Sie hier unter https://stackoverflow.com/users/704327/michael-merickel .
Die andere Sache zu beachten ist, dass diese Implementierung ziemlich einfach ist und nicht alle Methoden implementiert, die Sie möglicherweise benötigen. Sie müssen diese nach Bedarf in die DictProxy- oder ListProxy-Objekte schreiben.
quelle
x.__dict__.update(d)
sollte gut tun.quelle
__dict__
: Versuchobject().__dict__
und du wirstAttributeError: 'object' object has no attribute '__dict__'
Sie können das
json
Modul der Standardbibliothek mit einem benutzerdefinierten Objekt-Hook nutzen :Anwendungsbeispiel:
Und es ist nicht streng schreibgeschützt wie bei
namedtuple
, dh Sie können Werte ändern - nicht Struktur:quelle
json.JSONEncoder
und erweitern kannobject_hook
.Damit sollten Sie loslegen:
Es funktioniert noch nicht für Listen. Sie müssen die Listen in eine Benutzerliste einbinden und überladen
__getitem__
, um Diktate zu verpacken.quelle
if isinstance(d, list)
Klausel ausAnon
der Antwort von , damit es für Listen funktioniert .Ich weiß, dass es hier bereits viele Antworten gibt und ich bin zu spät zur Party, aber diese Methode konvertiert rekursiv und 'an Ort und Stelle' ein Wörterbuch in eine objektähnliche Struktur ... Funktioniert in 3.xx.
quelle
quelle
Lassen Sie mich eine Lösung erklären, die ich vor einiger Zeit fast verwendet habe. Aber zuerst wird der Grund, warum ich es nicht getan habe, durch die Tatsache veranschaulicht, dass der folgende Code:
gibt diesen Fehler:
Da "from" ein Python-Schlüsselwort ist, gibt es bestimmte Wörterbuchschlüssel, die Sie nicht zulassen können.
Jetzt ermöglicht meine Lösung den Zugriff auf die Wörterbuchelemente, indem deren Namen direkt verwendet werden. Sie können aber auch die "Wörterbuchsemantik" verwenden. Hier ist der Code mit Beispielverwendung:
quelle
Alte Fragen und Antworten, aber ich bekomme noch etwas zu reden. Es scheint, als würde niemand über rekursives Diktat sprechen. Das ist mein Code:
quelle
Wollte meine Version dieses kleinen Paradigmas hochladen.
Die Attribute für den Typ, der in die Klasse importiert wird, bleiben erhalten. Mein einziges Anliegen wäre es, Methoden aus dem Wörterbuch zu überschreiben, die Sie analysieren. Aber sonst scheint solide!
quelle
df.a
funktioniert nicht einmal.Das funktioniert auch gut
quelle
Hier ist eine andere Möglichkeit, den ursprünglichen Vorschlag von SilentGhost umzusetzen:
quelle
Ich stolperte über den Fall, dass ich eine Liste von Diktaten rekursiv in eine Liste von Objekten konvertieren musste. Basierend auf Robertos Ausschnitt hier, was hat die Arbeit für mich getan:
Beachten Sie, dass jedes Tupel aus offensichtlichen Gründen in sein Listenäquivalent konvertiert wird.
Hoffe, das hilft jemandem genauso wie all deine Antworten für mich, Jungs.
quelle
Was die Zuordnung über nur Ihre
dict
zu den__dict__
einem leeren Objekt?Dies schlägt natürlich bei Ihrem verschachtelten Diktatbeispiel fehl, es sei denn, Sie gehen das Diktat rekursiv durch:
Und Ihr Beispiellistenelement sollte wahrscheinlich
Mapping
eine Liste von (Schlüssel-, Wert-) Paaren wie folgt sein:quelle
Hier ist eine weitere Implementierung:
[Bearbeiten] Es fehlte etwas, um auch Diktate in Listen zu behandeln, nicht nur andere Diktate. Fix hinzugefügt.
quelle
Verwendungszweck:
quelle
Wie wäre es damit:
Dies kann dann folgendermaßen verwendet werden:
quelle
Ich denke, ein Diktat besteht aus Zahl, Zeichenfolge und Diktat reicht meistens aus. Daher ignoriere ich die Situation, dass Tupel, Listen und andere Typen nicht in der endgültigen Dimension eines Diktats erscheinen.
In Anbetracht der Vererbung in Kombination mit der Rekursion wird das Druckproblem bequem gelöst und es gibt zwei Möglichkeiten zum Abfragen von Daten, eine Möglichkeit zum Bearbeiten von Daten.
Sehen Sie sich das folgende Beispiel an, ein Diktat, das einige Informationen über Schüler beschreibt:
Ergebnisse:
quelle
Normalerweise möchten Sie die Diktathierarchie in Ihr Objekt spiegeln, jedoch keine Liste oder Tupel, die sich normalerweise auf der niedrigsten Ebene befinden. So habe ich das gemacht:
So machen wir es:
und bekomme:
x.b.b1.x
1x.c
['hi', 'bar']quelle
Mein Wörterbuch hat dieses Format:
Wie zu sehen ist, habe ich Wörterbücher und eine Liste von Diktaten verschachtelt . Dies liegt daran, dass addr_bk aus Protokollpufferdaten dekodiert wurde, die mit lwpb.codec in ein Python-Dikt konvertiert wurden. Es gibt ein optionales Feld (z. B. E-Mail => wo der Schlüssel möglicherweise nicht verfügbar ist) und ein wiederholtes Feld (z. B. Telefon => in Diktatliste konvertiert).
Ich habe alle oben vorgeschlagenen Lösungen ausprobiert. Einige verarbeiten die verschachtelten Wörterbücher nicht gut. Andere können die Objektdetails nicht einfach drucken.
Nur die Lösung dict2obj (dict) von Dawie Strauss funktioniert am besten.
Ich habe es ein wenig verbessert, um damit umzugehen, wenn der Schlüssel nicht gefunden werden kann:
Dann habe ich es getestet mit:
quelle
Aufbauend auf meiner Antwort auf " Python: Wie füge ich einer Klasse dynamisch Eigenschaften hinzu? ":
Sie rufen
makedata
das Wörterbuch auf, das Sie konvertieren möchten, odertrydata
abhängig davon, was Sie als Eingabe erwarten, und es spuckt ein Datenobjekt aus.Anmerkungen:
trydata
wenn Sie mehr Funktionen benötigen.x.a = {}
oder ähnliches.quelle