Wie konvertiert man ein verschachteltes Python-Diktat in ein Objekt?

Lesezeit: 6 Minuten

Benutzer-Avatar
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.

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, 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.

    – 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

Benutzer-Avatar
Kontinuität

Ü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'

Eine Python 3-Bibliothek ist unter verfügbar https://github.com/Infinidat/munch – Kredit geht an codyzu

>>> from munch import DefaultMunch
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> obj = DefaultMunch.fromDict(d)
>>> obj.b.c
2
>>> obj.a
1
>>> obj.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.

    – GDorn

    23. Juli 2015 um 22:31 Uhr

  • Neugierig, wie dies im Vergleich zu JSONpath abschneidet github.com/kennknowles/python-jsonpath-rw

    – MarkHu

    20. April 2016 um 18:55 Uhr

  • 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

Benutzer-Avatar
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

Benutzer-Avatar
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

Benutzer-Avatar
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

1127510cookie-checkWie konvertiert man ein verschachteltes Python-Diktat in ein Objekt?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy