2012-04-05 63 views
8

Pracuję z zagnieżdżonymi strukturami danych podobnymi do JSON w python 2.7, które wymieniam z obcym kodem perl. Po prostu chcę "pracować" z tymi zagnieżdżonymi strukturami list i słowników w sposób amoronowy.Używanie kluczy JSON jako atrybutów w zagnieżdżonych JSON

Więc jeśli mam strukturę tak ...

a = { 
    'x': 4, 
    'y': [2, 3, { 'a': 55, 'b': 66 }], 
} 

... Chcę być w stanie poradzić sobie z nim w skrypcie Pythona jakby był zagnieżdżone klas Python/elemencie, tak :

>>> aa = j2p(a) # <<- this is what I'm after. 
>>> print aa.x 
4 
>>> aa.z = 99 
>>> print a 
{ 
    'x': 4, 
    'y': [2, 3, { 'a': 55, 'b': 66 }], 
    'z': 99 
} 

>>> aa.y[2].b = 999 

>>> print a 
{ 
    'x': 4, 
    'y': [2, 3, { 'a': 55, 'b': 999 }], 
    'z': 99 
} 

Tak więc aa jest pełnomocnikiem w pierwotnej strukturze. Oto, do czego do tej pory doszedłem, zainspirowane doskonałym pytaniem o numer What is a metaclass in Python?.

def j2p(x): 
    """j2p creates a pythonic interface to nested arrays and 
    dictionaries, as returned by json readers. 

    >>> a = { 'x':[5,8], 'y':5} 
    >>> aa = j2p(a) 
    >>> aa.y=7 
    >>> print a 
    {'x': [5, 8], 'y':7} 
    >>> aa.x[1]=99 
    >>> print a 
    {'x': [5, 99], 'y':7} 

    >>> aa.x[0] = {'g':5, 'h':9} 
    >>> print a 
    {'x': [ {'g':5, 'h':9} , 99], 'y':7} 
    >>> print aa.x[0].g 
    5 
    """ 
    if isinstance(x, list): 
     return _list_proxy(x) 
    elif isinstance(x, dict): 
     return _dict_proxy(x) 
    else: 
     return x 

class _list_proxy(object): 
    def __init__(self, proxied_list): 
     object.__setattr__(self, 'data', proxied_list) 
    def __getitem__(self, a): 
     return j2p(object.__getattribute__(self, 'data').__getitem__(a)) 
    def __setitem__(self, a, v): 
     return object.__getattribute__(self, 'data').__setitem__(a, v) 


class _dict_proxy(_list_proxy): 
    def __init__(self, proxied_dict): 
     _list_proxy.__init__(self, proxied_dict) 
    def __getattribute__(self, a): 
     return j2p(object.__getattribute__(self, 'data').__getitem__(a)) 
    def __setattr__(self, a, v): 
     return object.__getattribute__(self, 'data').__setitem__(a, v) 


def p2j(x): 
    """p2j gives back the underlying json-ic json-ic nested 
    dictionary/list structure of an object or attribute created with 
    j2p. 
    """ 
    if isinstance(x, (_list_proxy, _dict_proxy)): 
     return object.__getattribute__(x, 'data') 
    else: 
     return x 

Teraz zastanawiam się, czy istnieje elegancki sposób mapowania cały zestaw z __*__ funkcji specjalnych, jak __iter__, __delitem__? więc nie trzeba rozpakowywać rzeczy przy użyciu p2j() tylko po to, aby powtarzać lub wykonywać inne pythonicowe rzeczy.

# today: 
for i in p2j(aa.y): 
    print i 
# would like to... 
for i in aa.y: 
    print i 
+0

myślę szukasz to rozwiązanie - http://stackoverflow.com/questions/4984647/accessing-dict-keys-like-an-attribute-in-python#answer-14620633 – Yurik

Odpowiedz

3

Jest an attrdict library że robi dokładnie to, że w bardzo bezpieczny sposób, ale jeśli chcesz, podejście szybkie i brudne (pamięć możliwie przecieka) zostało wydane w this answer:

class AttrDict(dict): 
    def __init__(self, *args, **kwargs): 
     super(AttrDict, self).__init__(*args, **kwargs) 
     self.__dict__ = self 

j = '{"y": [2, 3, {"a": 55, "b": 66}], "x": 4}' 
aa = json.loads(j, object_hook=AttrDict) 
11

myślę robisz to bardziej skomplikowane niż to musi być. Jeśli rozumiem zostanie poprawnie, wszystko powinno trzeba zrobić to:

import json 

class Struct(dict): 
    def __getattr__(self, name): 
     return self[name] 

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

    def __delattr__(self, name): 
     del self[name] 

j = '{"y": [2, 3, {"a": 55, "b": 66}], "x": 4}' 

aa = json.loads(j, object_hook=Struct) 

for i in aa.y: 
    print(i) 

Podczas ładowania JSON, parametr object_hook pozwala określić wpłacone obiekt do przetwarzania obiektów, które ładuje. Właśnie użyłem go, aby przekształcić dyktat w obiekt, który pozwala na dostęp atrybutów do jego kluczy. Docs

+0

To interesujące podejście. Jednak wygląda na to, że tracę leżące u podstaw zagnieżdżone 'dict()' z 'list()' struktury 'dict()', nigdy nie jest skonstruowane nawet. I polegam na tym. –

+0

@SusanneOberhauser: Nie jestem do końca pewien co masz na myśli. Będzie to po prostu 'Struct()' z 'list()' z 'Struct()'. 'isinstance (aa, dict)' powinno nadal działać, jak podstruktury Struct dyktują, i nadal możesz użyć 'aa ['y']' notacji, jeśli jej potrzebujesz. Wygląda na to, że łatwo byłoby zaadaptować do tego kod. –

+0

Zdałem sobie sprawę, że jeśli dodaję zagnieżdżone podstruktury jako 'Struct' zamiast' dict', zbliżam się do tego, co zamierzam, o ile nie dojdzie do kolizji nazw między atrybutami "dyktatu" a atrybutami słownika. 'aa.items' jest wbudowaną metodą' Struct', ale jest kluczem do dyktowania '_dict_proxy'. więc 'aa.copy = 44' działa zgodnie z przeznaczeniem w drugim, ale nie w pierwszym. Myślę, że naprawdę chciałbym zrozumieć, jak zmapować cały zestaw funkcji składowych do obiektu pośredniczącego za pomocą programowania meta python. –

Powiązane problemy