Die Bunch- Antwort ist in Ordnung, aber es fehlt an Rekursion und richtig __repr__
und__eq__
Ordnung, Funktionen, um zu simulieren, was Sie bereits mit einem Diktat tun können. Der Schlüssel zur Rekursion liegt auch nicht nur in der Rekursion von Diktaten, sondern auch in Listen, sodass Diktate in Listen ebenfalls konvertiert werden.
Ich hoffe, dass diese beiden Optionen Ihre Anforderungen erfüllen (möglicherweise müssen Sie die Typprüfungen __elt()
für komplexere Objekte anpassen ; diese wurden hauptsächlich bei JSON-Importen getestet, also sehr einfache Kerntypen).
- Der Bunch- Ansatz (gemäß vorheriger Antwort) - Objekt nimmt ein Diktat und konvertiert es rekursiv.
repr(obj)
gibt zurück Bunch({...})
, das in ein äquivalentes Objekt neu interpretiert werden kann.
class Bunch(object):
def __init__(self, adict):
"""Create a namespace object from a dict, recursively"""
self.__dict__.update({k: self.__elt(v) for k, v in adict.items()})
def __elt(self, elt):
"""Recurse into elt to create leaf namepace objects"""
if type(elt) is dict:
return type(self)(elt)
if type(elt) in (list, tuple):
return [self.__elt(i) for i in elt]
return elt
def __repr__(self):
"""Return repr(self)."""
return "%s(%s)" % (type(self).__name__, repr(self.__dict__))
def __eq__(self, other):
return self.__dict__ == other.__dict__
- Der SimpleNamespace Ansatz - da
types.SimpleNamespace
bereits implementiert __repr__
und __eq__
alles, was Sie brauchen , ist eine rekursive zu implementieren __init__
Methode:
import types
class RecursiveNamespace(types.SimpleNamespace):
def __init__(self, **kwargs):
"""Create a SimpleNamespace recursively"""
self.__dict__.update({k: self.__elt(v) for k, v in kwargs.items()})
def __elt(self, elt):
"""Recurse into elt to create leaf namepace objects"""
if type(elt) is dict:
return type(self)(**elt)
if type(elt) in (list, tuple):
return [self.__elt(i) for i in elt]
return elt
Die RecursiveNamespace- Klasse verwendet Schlüsselwortargumente, die natürlich aus einem de-referenzierten Diktat (ex **mydict
) stammen können.
Lassen Sie uns sie jetzt auf die Probe stellen:
adict = {'foo': 'bar', 'baz': [{'aaa': 'bbb', 'ccc': 'ddd'}]}
a = Bunch(adict)
b = RecursiveNamespace(**adict)
print('a:', str(a))
print('b:', str(b))
print('a == b :', str(a == b))
Das Ergebnis ist:
a: Bunch({'foo': 'bar', 'baz': [Bunch({'aaa': 'bbb', 'ccc': 'ddd'})]})
b: RecursiveNamespace(baz=[RecursiveNamespace(aaa='bbb', ccc='ddd')], foo='bar')
a == b : True
Obwohl es sich um unterschiedliche Klassen handelt, da beide mit äquivalenten Namespaces initialisiert wurden und ihre __eq__
Methode nur den Namespace ( self.__dict__
) vergleicht, wird beim Vergleich der beiden Namespace-Objekte zurückgegebenTrue
Möglicherweise stellen Sie auch fest, dass ich die type(self)(...)
Verwendung des Klassennamens anstelle der Verwendung des Klassennamens verwende. Dies hat zwei Vorteile: Erstens kann die Klasse umbenannt werden, ohne dass rekursive Aufrufe aktualisiert werden müssen, und zweitens, wenn die Klasse in eine Unterklasse unterteilt ist, wird eine Rekursion unter Verwendung des Unterklassennamens durchgeführt. Es ist auch der Name, der in __repr__
( type(self).__name__
) verwendet wird.