Python實現支援JSON儲存和解析的物件

Adan的部落格發表於2014-12-03

我們知道利用JSON模組可方便的將Python基本型別(dict、list等)資料永久的儲存成檔案,同時也可以通過自定義轉換函式和繼承JSON encode&decode的方法實現自定義類的儲存。本文就在前文“ Python JSON模組”的基礎上,實現python支援JSON儲存的物件。

物件能夠採取JSON儲存和解析是有很大意義的。例如機器學習中所有分類演算法的訓練過程中都存在大量的資料計算,如果每次啟動分類都需要重新訓練分類演算法浪費資源且沒有效率,如果能夠將訓練產生的分類演算法物件儲存起來,那麼除非需要演算法調優,以後只需載入即可。另一方面,物件能夠進行JSON解析和儲存也使得其可以在網路上傳送,這在當下雲端計算、分散式資料處理中都有非凡的意義。

為了實現自儲存和解析,定義物件的關鍵操作有:

0,將object_json.py copy至包中,定義物件的模組匯入object_json:import object_json。

1,__init__()函式要支援可變數量的函式呼叫,即要寫成__init__(self, …, , **args)。如此定義物件才可以有除構造階段需要初始化的屬性之外的屬性。

2,對於物件構造階段必須初始化的屬性,__init__()函式中的形參必須與這些屬性名稱完全相同,如此才能通過字典‘key’: value對構造物件。

3,定義一個屬性‘__name__’–該物件例項的名稱,利用inspect模組實現。‘__name__‘屬性主要用於產生物件儲存時預設的檔名稱。

4,定義jsonDumps()和jsonLoadTransfer()方法,通過objectLoadFromFile()完成物件JSON檔案load和新物件建立。

(i)jsonDumps()用於將物件轉換成dict並通過json.dumps()將物件儲存成json檔案,若使用者不指定檔名則以instancename.json為預設儲存檔案。由於JSON只支援python基本型別,因此若物件中有一些其他型別(如numpy matrix),則需將其轉化成Python基本型別(如matrix.tolist()將matrix轉換成list)。

(ii)jsonLoadTransfer()用於完成資料格式的轉換,將一些物件屬性從基本型別轉化成需要的型別(如mat(list)將型別從list轉換成matrix),若物件只有Python基本型別則可以省略該方法。建立完整、可用物件過程是:

obj = objectLoadFromFile()   
obj.jsonLoadTransfer()

下面的程式碼就是支援自定義物件進行JSON儲存和解析的object_json模組原始碼。

import json   
import inspect    
import pdb   
def object2dict(obj):      
    #convert object to a dict      
    d = {'__class__':obj.__class__.__name__, '__module__':obj.__module__}      
    d.update(obj.__dict__)      
    return d   
def objectDumps2File(obj, jsonfile):   
    objDict = object2dict(obj)   
    with open(jsonfile, 'w') as f:   
        f.write(json.dumps(objDict))   

def dict2object(d):      
    '''convert dict to object, the dict will be changed'''       
    if'__class__' in d:      
        class_name = d.pop('__class__')      
        module_name = d.pop('__module__')      
        module = __import__(module_name)      
        #print 'the module is:', module      
        class_ = getattr(module,class_name)      
        args = dict((key.encode('ascii'), value) for key, value in d.items()) #get args     
        #print 'the atrribute:', repr(args)   
        #pdb.set_trace()   
        inst = class_(**args) #create new instance      
    else:      
        inst = d      
    return inst   
def objectLoadFromFile(jsonFile):   
    '''load json file and generate a new object instance whose __name__ filed  
    will be 'inst' '''  
    with open(jsonFile) as f:   
        objectDict =json.load(f)   
    obj = dict2object(objectDict)   
    return obj   
#test function      
if __name__  == '__main__':   
    class Person(object):      
        def __init__(self,name,age, **args):   
            obj_list = inspect.stack()[1][-2]   
            self.__name__ = obj_list[0].split('=')[0].strip()#object instance name   
            self.name = name      
            self.age = age   

        def __repr__(self):      
            return 'Person Object name : %s , age : %d' % (self.name,self.age)   
        def say(self):   
            #d = inspect.stack()[1][-2]   
            #print d[0].split('.')[0].strip()   
            return self.__name__  
        def jsonDumps(self, filename=None):   
            '''essential transformation to Python basic type in order to  
            store as json. dumps as objectname.json if filename missed '''  
            if not filename:   
                jsonfile = self.__name__+'.json'   
            else: jsonfile = filename   
            objectDumps2File(self, jsonfile)   

        def jsonLoadTransfer(self):#TBD   
            '''essential transformation to object required type,such as  
            numpy matrix.call this function after newobject = objectLoadFromFile(jsonfile)'''  
            pass  

    p = Person('Aidan',22)        
    #json.dumps(p)#error will be throwed   

    #objectDumps2File(p,'Person.json')   
    p.jsonDumps()   
    p_l = objectLoadFromFile('p.json')   

    print 'the decoded obj type: %s, obj:%s' % (type(p_l),repr(p_l))

Python類有新舊兩種,py 2.2 後類定義繼承 object 的目的是使這個類成為 new style class, 沒有繼承 object 的為傳統classic class(最終也會繼承object)。

類定義中如下兩種方法:

class Person():   
class Person(object)

其區別在於:

若建立新的Person instanc test,則type(test)的輸出分別為:

<type 'instance'>   
<class '__main__.Person'>

inspect 模組提供了一系列自省函式,它可以獲取模組,類,方法,函式,traceback,幀物件,程式碼物件的資訊。常用的方法getmembers,ismodule,getcallargs,isclass等,更多詳細資訊參見:http://docs.python.org/library/inspect.html。

相關文章