Wie konvertiert man ein verschachteltes Python-Diktat in ein Objekt?
Lesezeit: 6 Minuten
Markus
Ich suche nach einer eleganten Möglichkeit, Daten mithilfe des Attributzugriffs auf ein Diktat mit einigen verschachtelten Diktaten und Listen (dh Objektsyntax im JavaScript-Stil) abzurufen.
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar
Ich denke, das ist ohne Rekursion nicht möglich, aber was wäre ein schöner Weg, um einen Objektstil für Diktate zu bekommen?
Ich habe kürzlich versucht, etwas Ähnliches zu tun, aber ein wiederkehrender Wörterbuchschlüssel (“from” – was ein Python-Schlüsselwort ist) hat mich daran gehindert, es durchzuziehen. Denn sobald Sie versucht haben, mit “x.from” auf dieses Attribut zuzugreifen, erhalten Sie einen Syntaxfehler.
– Dawie Strauss
20. August 2009 um 13:08 Uhr
Das ist in der Tat ein Problem, aber ich kann auf “from” verzichten, um das Leben beim Zugriff auf große dict-Konstrukte einfacher zu machen 🙂 indem ich x eintippe[‘a’][‘d’][1][‘foo’] ist echt nervig, also xad[1].foo-Regeln. Wenn Sie from benötigen, können Sie über getattr(x, ‘from’) darauf zugreifen oder stattdessen _from als Attribut verwenden.
Die meisten dieser “Lösungen” scheinen nicht zu funktionieren (selbst die akzeptierte erlaubt keine verschachtelten d1.b.c), Ich denke, es ist klar, dass Sie etwas aus einer Bibliothek verwenden sollten, z benanntes Tupel aus Sammlungenwie diese Antwort andeutet, …
Überraschenderweise hat niemand erwähnt Bündel. Diese Bibliothek soll ausschließlich den Zugriff auf Attributstile auf Diktatobjekte ermöglichen und macht genau das, was das OP will. Eine Demonstration:
>>> from bunch import bunchify
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = bunchify(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
Und es gibt einen mit Python 3 kompatiblen (scheinbar 2.6-3.4) Zweig von Bunch namens Munch: github.com/Infinidat/munch
– codyzu
28. Juli 2014 um 20:19 Uhr
Bunch ist die beste Lösung von all diesen, da es mehrere Arten der Serialisierung gut unterstützt und gewartet wird. Grosses Dankeschön. Ich wünschte, die Python3-Version würde den gleichen Namen tragen, warum nicht.
– Jonathan
9. Februar 2015 um 20:30 Uhr
Also nur eine Vorwarnung, Bunch und Attrdict sind übrigens auch sehr langsam. Sie verbrauchten etwa 1/3 bzw. 1/2 meiner Anfragezeit, als sie eine häufige Verwendung in unserer Anwendung sahen. Definitiv nichts zu ignorieren. Sprechen Sie mehr darüber unter stackoverflow.com/a/31569634/364604.
– JayD3e
22. Juli 2015 um 17:08 Uhr
Dies ermöglicht zwar einen objektähnlichen Zugriff auf Diktate, jedoch über getattr. Dies erschwert die Selbstbeobachtung in intelligenten REPLs wie IPython.
Gut! Ich würde jedoch .items() durch .iteritems() ersetzen, um den Speicherbedarf zu verringern.
– Eric O. Lebigot
20. August 2009 um 13:58 Uhr
Wenn es keine OP-Anforderung ist, ist dies kein Problem – aber beachten Sie, dass dies Objekte in Listen innerhalb von Listen nicht rekursiv verarbeitet.
– Anonym
20. August 2009 um 14:09 Uhr
Mir ist klar, dass dies eine alte Antwort ist, aber heutzutage wäre es besser, eine zu verwenden abstrakte Basisklasse statt dieser hässlichen Linie if isinstance(b, (list, tuple)):
– Wim
30. April 2013 um 1:15 Uhr
Tipp: Haben Sie die obj Klasse erben von argparse.Namespace für zusätzliche Funktionen wie lesbare Zeichenfolgendarstellung.
– Serano
11. April 2014 um 15:27 Uhr
Abhängig vom Anwendungsfall würden wir normalerweise überprüfen, ob dies der Fall ist nicht ein String-Typ, aber das ist es ist ein Sequenztyp
– Wim
29. März 2015 um 2:22 Uhr
SilentGhost
x = type('new_dict', (object,), d)
dann fügen Sie Rekursion hinzu und Sie sind fertig.
bearbeiten so würde ich es umsetzen:
>>> d
{'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> def obj_dic(d):
top = type('new', (object,), d)
seqs = tuple, list, set, frozenset
for i, j in d.items():
if isinstance(j, dict):
setattr(top, i, obj_dic(j))
elif isinstance(j, seqs):
setattr(top, i,
type(j)(obj_dic(sj) if isinstance(sj, dict) else sj for sj in j))
else:
setattr(top, i, j)
return top
>>> x = obj_dic(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
Warum erstellen Sie Typobjekte und instanziieren sie nicht? Wäre das nicht logischer? Ich meine, warum nicht top_instance = top() und das zurückbringen, wohin du zurückkehrst top?
– Pfannkuchen
21. Januar 2014 um 0:14 Uhr
Schön für die “Blatt” -Daten, aber die Beispiele lassen praktischerweise “Zweige” wie aus x und x.b die hässlich zurückgeben <class '__main__.new'>
– MarkHu
16. Oktober 2014 um 3:12 Uhr
David Golembiowski
# Applies to Python-3 Standard Library
class Struct(object):
def __init__(self, data):
for name, value in data.items():
setattr(self, name, self._wrap(value))
def _wrap(self, value):
if isinstance(value, (tuple, list, set, frozenset)):
return type(value)([self._wrap(v) for v in value])
else:
return Struct(value) if isinstance(value, dict) else value
# Applies to Python-2 Standard Library
class Struct(object):
def __init__(self, data):
for name, value in data.iteritems():
setattr(self, name, self._wrap(value))
def _wrap(self, value):
if isinstance(value, (tuple, list, set, frozenset)):
return type(value)([self._wrap(v) for v in value])
else:
return Struct(value) if isinstance(value, dict) else value
Kann mit jeder Sequenz/Diktat/Wert-Struktur beliebiger Tiefe verwendet werden.
Warum erstellen Sie Typobjekte und instanziieren sie nicht? Wäre das nicht logischer? Ich meine, warum nicht top_instance = top() und das zurückbringen, wohin du zurückkehrst top?
– Pfannkuchen
21. Januar 2014 um 0:14 Uhr
Schön für die “Blatt” -Daten, aber die Beispiele lassen praktischerweise “Zweige” wie aus x und x.b die hässlich zurückgeben <class '__main__.new'>
– MarkHu
16. Oktober 2014 um 3:12 Uhr
Wim
Es wird ein Sammelhelfer gerufen namedtupledas kann dies für Sie tun:
from collections import namedtuple
d_named = namedtuple('Struct', d.keys())(*d.values())
In [7]: d_named
Out[7]: Struct(a=1, b={'c': 2}, d=['hi', {'foo': 'bar'}])
In [8]: d_named.a
Out[8]: 1
Dies beantwortet nicht die Frage der Rekursion für die verschachtelten Diktate.
– Derigierbar
21. Oktober 2013 um 22:40 Uhr
Sie können benannte Tupel nicht ändern.
– max
14. Juli 2016 um 20:16 Uhr
Können wir garantieren, dass die Reihenfolge der von keys() und values() zurückgegebenen Liste der Reihe nach übereinstimmt? Ich meine, wenn es ein OrderedDict ist, ja. Aber ein Standarddiktat? Ich weiß, dass CPython 3.6+ und PyPy “compact” Diktate bestellt werden, aber die Dokumentation zitieren: “Der ordnungserhaltende Aspekt dieser neuen Implementierung wird als Implementierungsdetail betrachtet und sollte nicht als verlässlich angesehen werden.”
– Hawok
18. April 2017 um 6:27 Uhr
das geht auch d_named = namedtuple('Struct', d)(**d)
– xiaobing
21. Januar 2021 um 6:36 Uhr
11275100cookie-checkWie konvertiert man ein verschachteltes Python-Diktat in ein Objekt?yes
Ich habe kürzlich versucht, etwas Ähnliches zu tun, aber ein wiederkehrender Wörterbuchschlüssel (“from” – was ein Python-Schlüsselwort ist) hat mich daran gehindert, es durchzuziehen. Denn sobald Sie versucht haben, mit “x.from” auf dieses Attribut zuzugreifen, erhalten Sie einen Syntaxfehler.
– Dawie Strauss
20. August 2009 um 13:08 Uhr
Das ist in der Tat ein Problem, aber ich kann auf “from” verzichten, um das Leben beim Zugriff auf große dict-Konstrukte einfacher zu machen 🙂 indem ich x eintippe[‘a’][‘d’][1][‘foo’] ist echt nervig, also xad[1].foo-Regeln. Wenn Sie from benötigen, können Sie über getattr(x, ‘from’) darauf zugreifen oder stattdessen _from als Attribut verwenden.
– Markus
20. August 2009 um 15:51 Uhr
from_
statt_from
entsprechend PEP 8.– Kos
14. Januar 2013 um 7:32 Uhr
Die meisten dieser “Lösungen” scheinen nicht zu funktionieren (selbst die akzeptierte erlaubt keine verschachtelten
d1.b.c
), Ich denke, es ist klar, dass Sie etwas aus einer Bibliothek verwenden sollten, z benanntes Tupel aus Sammlungenwie diese Antwort andeutet, …– Andy Hayden
29. April 2013 um 14:50 Uhr
Bunch – Verwenden Sie ein Python-Diktat wie ein Objekt: thechangelog.com/bunch-lets-use-python-dict-like-object
– Markus
10. März 2014 um 17:23 Uhr