657 Stimmen

Verschachtelte Python-Diktate in Objekte umwandeln?

Ich bin auf der Suche nach einem eleganten Weg, um Daten mit Attribut Zugriff auf ein Diktat mit einigen verschachtelten Dicts und Listen (d.h. Javascript-Stil Objekt-Syntax) zu erhalten.

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 nicht möglich, ohne Rekursion, aber was wäre ein schöner Weg, um ein Objekt-Stil für Dicts zu erhalten?

6 Stimmen

Ich habe vor kurzem versucht, etwas Ähnliches zu tun, aber ein wiederkehrender Wörterbuchschlüssel ("from" - ein Python-Schlüsselwort) hat mich daran gehindert, es zu tun. Denn sobald man versuchte, mit "x.from" auf dieses Attribut zuzugreifen, erhielt man einen Syntaxfehler.

3 Stimmen

Das ist in der Tat ein Problem, aber ich kann auf "from" verzichten, um das Leben einfacher zu machen, wenn ich auf große Diktatkonstrukte zugreife:) die Eingabe von x['a']['d'][1]['foo'] ist wirklich lästig, also gilt x.a.d[1].foo. wenn Sie from benötigen, können Sie über getattr(x, 'from') darauf zugreifen oder stattdessen _from als Attribut verwenden.

7 Stimmen

from_ statt _from laut PEP 8 .

1voto

Max Sirwa Punkte 135

Aufbauend auf dem, was zuvor durch die akzeptierte Antwort getan wurde, wenn Sie es rekursiv haben möchten.

class FullStruct:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            if isinstance(value, dict):
                f = FullStruct(**value)
                self.__dict__.update({key: f})
            else:
                self.__dict__.update({key: value})

1voto

David X Punkte 3618

Aufbauend auf meiner Antwort auf " python: Wie kann man einer Klasse dynamisch eine Eigenschaft hinzufügen? ":

class data(object):
    def __init__(self,*args,**argd):
        self.__dict__.update(dict(*args,**argd))

def makedata(d):
    d2 = {}
    for n in d:
        d2[n] = trydata(d[n])
    return data(d2)

def trydata(o):
    if isinstance(o,dict):
        return makedata(o)
    elif isinstance(o,list):
        return [trydata(i) for i in o]
    else:
        return o

Sie rufen makedata auf das Wörterbuch, das Sie konvertieren wollen, oder vielleicht trydata je nachdem, was Sie als Eingabe erwarten, und es spuckt ein Datenobjekt aus.

Anmerkungen:

  • Sie können elifs hinzufügen zu trydata wenn Sie mehr Funktionalität benötigen.
  • Das funktioniert natürlich nicht, wenn Sie x.a = {} oder ähnlich.
  • Wenn Sie eine schreibgeschützte Version wünschen, verwenden Sie die Klassendaten von die ursprüngliche Antwort .

1voto

Sie können es auf meine Weise handhaben.

somedict= {"person": {"name": "daniel"}}

class convertor:
    def __init__(self, dic: dict) -> object:
        self.dict = dic

        def recursive_check(obj):
            for key, value in dic.items():
                if isinstance(value, dict):
                    value= convertor(value)
                setattr(obj, key, value)
        recursive_check(self)
my_object= convertor(somedict)

print(my_object.person.name)

1voto

hokage555 Punkte 63

Suche nach einer einfachen Wrapper-Klasse für dict Ermöglichung des Zugriffs auf bzw. der Zuweisung von Attributen (Punktnotation) Ich war mit den bestehenden Optionen aus den folgenden Gründen nicht zufrieden.

dataclasses , pydantic usw. sind großartig, erfordern aber eine statische Definition des Inhalts. Außerdem können sie nicht ersetzen dict in Code, der sich auf dict da sie nicht dieselben Methoden und __getitem__() Syntax wird nicht unterstützt.

Daher habe ich Folgendes entwickelt MetaDict . Es verhält sich genau wie dict sondern ermöglicht die Punktnotation und die automatische IDE-Vervollständigung (wenn das Objekt im RAM geladen ist) ohne die Unzulänglichkeiten und potenziellen Namensraumkonflikte anderer Lösungen. Alle Funktionen und Anwendungsbeispiele können auf GitHub gefunden werden (siehe Link oben).

Vollständige Offenlegung: Ich bin der Autor von MetaDict .

Unzulänglichkeiten/Einschränkungen, auf die ich beim Ausprobieren anderer Lösungen gestoßen bin:

  • Süchtig
    • Keine automatische Tastenvervollständigung in der IDE
    • Verschachtelte Tastenbelegung kann nicht ausgeschaltet werden
    • Neu zugewiesen dict Objekte werden nicht so konvertiert, dass sie den Schlüsselzugriff im Attributstil unterstützen
    • Eingebauter Schattentyp Dict
  • Prodikt
    • Keine automatische Schlüsselvervollständigung in der IDE ohne Definition eines statischen Schemas (ähnlich wie bei dataclass )
    • Keine rekursive Umwandlung von dict Objekte, wenn sie eingebettet sind in list oder andere eingebaute Iterabilien
  • AttrDict
    • Keine automatische Tastenvervollständigung in der IDE
    • Konvertiert list Objekte zu tuple hinter den Kulissen
  • Munch
    • Eingebaute Methoden wie items() , update() usw. können überschrieben werden mit obj.items = [1, 2, 3]
    • Keine rekursive Umwandlung von dict Objekte, wenn sie eingebettet sind in list oder andere eingebaute Iterabilien
  • EasyDict
    • Nur Strings sind gültige Schlüssel, aber dict akzeptiert alle hashfähigen Objekte als Schlüssel
    • Eingebaute Methoden wie items() , update() usw. können überschrieben werden mit obj.items = [1, 2, 3]
    • Eingebaute Methoden verhalten sich nicht wie erwartet: obj.pop('unknown_key', None) wirft ein AttributeError

Hinweis: Ich habe eine ähnliche Antwort in diesem Stackoverflow der damit zusammenhängt.

0voto

thiago marini Punkte 450

Diese kleine Klasse bereitet mir keine Probleme, erweitern Sie sie einfach und verwenden Sie die copy()-Methode:

  import simplejson as json

  class BlindCopy(object):

    def copy(self, json_str):
        dic = json.loads(json_str)
        for k, v in dic.iteritems():
            if hasattr(self, k):
                setattr(self, k, v);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X