2012-04-05 66 views
8

我正在與python 2.7中的嵌套類JSON數據結構一起工作,這些數據結構與一些外部Perl代碼交換。我只想以'amore pythonic'的方式與這些嵌套的列表和詞典結構一起工作。在嵌套JSON中使用JSON鍵作爲屬性

所以,如果我有這樣的結構...

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

...我希望能夠在Python腳本來處理它,如果它是嵌套的Python類/的Structs,這樣:

>>> 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 
} 

因此,aa是原始結構的代理。這是我迄今爲止提出的,受到優秀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 

現在我不知道是否有映射一整套的__*__特殊功能的一個優雅的方式,像__iter____delitem__?所以我不需要使用p2j()來解開東西來迭代或執行其他pythonic東西。

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

我認爲你正在尋找此解決方案 - http://stackoverflow.com/questions/4984647/accessing-dict-keys-like-an-attribute-in-python#answer-14620633 – Yurik 2014-08-14 22:27:00

回答

3

an attrdict library所做的正是在一個非常安全的方式,但如果你想在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

我覺得你讓這件事情變得比需要的複雜。如果我理解正確的話,你應該需要做的是這樣的:

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) 

當加載JSON時,object_hook參數允許您指定一個可調用對象來處理它加載的對象。我剛剛用它將字典轉換爲允許屬性訪問其鍵的對象。 Docs

+0

這是一個有趣的方法。然而,它看起來像是釋放了'dict()'結構的'list()'的嵌套'dict()',它從來沒有構造過。我依賴於此。 – 2012-04-05 12:28:46

+0

@SusanneOberhauser:我不太清楚你的意思。它將簡單地是'Struct()'的'list()'的'Struct()'。 'isinstance(aa,dict)'應該仍然可以工作,因爲Struct子類字典,如果你需要它,你仍然可以使用'a'['y']'符號。這似乎很容易適應代碼。 – 2012-04-09 21:55:45

+0

我意識到,如果我將嵌套子結構添加爲'Struct'而不是'dict',那麼只要'dict'屬性和字典屬性之間沒有名稱衝突,就可以接近我的意圖。 'aa.items'是'Struct'的一種內置方法,但它是'_dict_proxy'字典中的一個關鍵字。所以'aa.copy = 44'在後者中按預期工作,但不在前者中。 我想我真的很想了解如何使用python meta編程將一整套成員函數映射到代理對象。 – 2012-04-10 12:49:50