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

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

8 Stimmen

from_ statt _from laut PEP 8 .

2voto

onno Punkte 1061

Wie wäre es damit:

from functools import partial
d2o=partial(type, "d2o", ())

Diese kann dann wie folgt verwendet werden:

>>> o=d2o({"a" : 5, "b" : 3})
>>> print o.a
5
>>> print o.b
3

1 Stimmen

Das ist keine Antwort auf die Frage. Der Autor möchte verschachtelte Diktate konvertieren. Versuchen Sie {'a': 1, 'b': {'b1': 2}} und Sie erhalten AttributeError

2voto

user222758 Punkte 12177
class Struct(dict):
    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        self[name] = value

    def copy(self):
        return Struct(dict.copy(self))

Verwendung:

points = Struct(x=1, y=2)
# Changing
points['x'] = 2
points.y = 1
# Accessing
points['x'], points.x, points.get('x') # 2 2 2
points['y'], points.y, points.get('y') # 1 1 1
# Accessing inexistent keys/attrs 
points['z'] # KeyError: z
points.z # AttributeError: z
# Copying
points_copy = points.copy()
points.x = 2
points_copy.x # 1

2voto

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 .

2voto

Brian Punkte 112487

Hier ist eine weitere Umsetzung:

class DictObj(object):
    def __init__(self, d):
        self.__dict__ = d

def dict_to_obj(d):
    if isinstance(d, (list, tuple)): return map(dict_to_obj, d)
    elif not isinstance(d, dict): return d
    return DictObj(dict((k, dict_to_obj(v)) for (k,v) in d.iteritems()))

[Bearbeiten] Verpasste Bit über auch Dicts innerhalb von Listen, nicht nur andere Dicts behandeln. Fix hinzugefügt.

0 Stimmen

Beachten Sie, dass die Einstellung Diktat auf das Quellwörterbuch bedeutet, dass alle Änderungen an den Attributen des resultierenden Objekts sich auch auf das Wörterbuch auswirken, das das Objekt erstellt hat, und umgekehrt. Dies kann zu unerwarteten Ergebnissen führen, wenn das Wörterbuch für etwas anderes als die Erstellung des Objekts verwendet wird.

0 Stimmen

@Mark: Tatsächlich wird jedes Mal ein neues Wörterbuch an DictObj übergeben, anstatt einfach dasselbe Dict-Objekt zu verwenden, so dass dies eigentlich nicht passiert. Es ist notwendig, dies zu tun, da ich das Diktat übersetzen muss. Werte auch innerhalb eines Wörterbuchs, so dass es unmöglich wäre, das ursprüngliche Diktatobjekt zu durchlaufen, ohne es selbst zu verändern.

0 Stimmen

Es gibt ziemlich viele Antworten darauf, die akzeptierte Antwort sah nicht so aus, als wäre sie rekursiv oder würde mit Listen umgehen. Ich habe sie alle durchgelesen und diese sah auf den ersten Blick am einfachsten aus, ich habe sie getestet und sie hat funktioniert. Tolle Antwort.

1voto

lajarre Punkte 4587

Hier ist eine verschachtelte Version mit namedtuple:

from collections import namedtuple

class Struct(object):
    def __new__(cls, data):
        if isinstance(data, dict):
            return namedtuple(
                'Struct', data.iterkeys()
            )(
                *(Struct(val) for val in data.values())
            )
        elif isinstance(data, (tuple, list, set, frozenset)):
            return type(data)(Struct(_) for _ in data)
        else:
            return data

\=>

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> s = Struct(d)
>>> s.d
['hi', Struct(foo='bar')]
>>> s.d[0]
'hi'
>>> s.d[1].foo
'bar'

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