Python JSON模塊

jopen 10年前發布 | 95K 次閱讀 Python開發 Python JSON

(一)什么是json:

JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。易于人閱讀和編寫。同時也易于機器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一個子集。JSON采用完全獨立于語言的文本格式,但是也使用了類似于C語言家族的習慣(包括C, C++, C#, Java, JavaScript, Perl, Python等)。這些特性使JSON成為理想的數據交換語言。

JSON建構于兩種結構:

“名稱/值”對的集合(A collection of name/value pairs)。不同的語言中,它被理解為對象(object),紀錄(record),結構(struct),字典(dictionary),哈希表(hash table),有鍵列表(keyed list),或者關聯數組 (associative array)。 

值的有序列表(An ordered list of values)。在大部分語言中,它被理解為數組(array)。 

這些都是常見的數據結構。事實上大部分現代計算機語言都以某種形式支持它們。這使得一種數據格式在同樣基于這些結構的編程語言之間交換成為可能。

(二)Python JSON模塊

Python2.6開始加入了JSON模塊,無需另外下載,Python的Json模塊序列化與反序列化的過程分別是 encoding和 decoding。encoding-把一個Python對象編碼轉換成Json字符串;decoding-把Json格式字符串解碼轉換成Python對象。要使用json模塊必須先導入:

import json

1,簡單數據類型的處理

Python JSON模塊可以直接處理簡單數據類型(string、unicode、int、float、list、tuple、dict)。 json.dumps()方法返回一個str對象,編碼過程中會存在從python原始類型向json類型的轉化過程,具體的轉化對照如下:

json.dumps方法提供了很多好用的參數可供選擇,比較常用的有sort_keys(對dict對象進行排序,我們知道默認dict是無序存放的)、separators,indent等參數,dumps方法的定義為:

json.dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True,cls=None, indent=None, separators=None, encoding="utf-8", default=None, sort_keys=False,**kw)

使用簡單的json.dumps方法對簡單數據類型進行編碼,例如:

    obj = [[1,2,3],123,123.123,'abc',{'key1':(1,2,3),'key2':(4,5,6)}]   
    encodedjson = json.dumps(obj)   
    print 'the original list:\n',obj   
    print 'length of obj is:',len(repr(obj))
    print 'repr(obj),replace whiteblank with *:\n', repr(obj).replace(' ','*')   
    print 'json encoded,replace whiteblank with *:\n',encodedjson.replace(' ','*')    

輸出:(Python默認的item separator是‘, ’(不是','),所以list無論是轉化成字符串還是json格式,成員之間都是有空格隔開的)

    the original list:   
    [[1, 2, 3], 123, 123.123, 'abc', {'key2': (4, 5, 6), 'key1': (1, 2, 3)}]  
    length of obj is: 72 
    repr(obj),replace whiteblank with *:   
    [[1,*2,*3],*123,*123.123,*'abc',*{'key2':*(4,*5,*6),*'key1':*(1,*2,*3)}]   
    json encoded,replace whiteblank with *:   
    [[1,*2,*3],*123,*123.123,*"abc",*{"key2":*[4,*5,*6],*"key1":*[1,*2,*3]}]   
    <type 'list'>  

我們接下來在對encodedjson進行decode,得到原始數據,需要使用的json.loads()函數。loads方法返回了原始的對象,但是仍然發生了一些數據類型的轉化,上例中‘abc’轉化為了unicode類型。需要注意的是,json字符串中的字典類型的key必須要用雙引號“”json.loads()才能正常解析。從json到python的類型轉化對照如下:

    decodejson = json.loads(encodedjson)   
    print 'the type of decodeed obj from json:', type(decodejson)   
    print 'the obj is:\n',decodejson   
    print 'length of decoded obj is:',len(repr(decodejson))  

輸出:

    the type of decodeed obj from json: <type 'list'>   
    the obj is:   
    [[1, 2, 3], 123, 123.123, u'abc', {u'key2': [4, 5, 6], u'key1': [1, 2, 3]}]   
    length of decoded obj is: 75  #比原obj多出了3個unicode編碼標示‘u’

sort_keys排序功能使得存儲的數據更加有利于觀察,也使得對json輸出的對象進行比較。下例中,data1和data2數據應該是一樣的,dict存儲的無序性造成兩者無法比較。

    data1 = {'b':789,'c':456,'a':123}   
    data2 = {'a':123,'b':789,'c':456}   
    d1 = json.dumps(data1,sort_keys=True)   
    d2 = json.dumps(data2)   
    d3 = json.dumps(data2,sort_keys=True)   
    print 'sorted data1(d1):',d1   
    print 'unsorted data2(d2):',d2   
    print 'sorted data2(d3):',d3   
    print 'd1==d2?:',d1==d2   
    print 'd1==d3?:',d1==d3  

輸出:

    sorted data1(d1): {"a": 123, "b": 789, "c": 456}   
    unsorted data2(d2): {"a": 123, "c": 456, "b": 789}   
    sorted data2(d3): {"a": 123, "b": 789, "c": 456}   
    d1==d2?: False  
    d1==d3?: True  

indent參數是縮進的意思,它可以使數據的存儲格式更優雅、可讀性更強,這是通過增加一些冗余的空格進行填充的。但是在解碼(json.loads())時,空白填充會被刪除。

    data = {'b':789,'c':456,'a':123}   
    d1 = json.dumps(data,sort_keys=True,indent=4)   
    print 'data len is:',len(repr(data))   
    print '4 indented data:\n',d1   
    d2 = json.loads(d1)   
    print 'decoded DATA:', repr(d2)   
    print 'len of decoded DATA:',len(repr(d2))  

輸出:(可見loads時會將dumps時增加的intent 填充空格去除)

    data len is: 30   
    4 indented data:   
    {   
        "a": 123,    
        "b": 789,    
        "c": 456   
    }   
    decoded DATA: {u'a': 123, u'c': 456, u'b': 789}   
    len of decoded DATA: 33  
json主要是作為一種數據通信的格式存在的,無用的空格會浪費通信帶寬,適當時候也要對數據進行壓縮。separator參數可以起到這樣的作用,該參數傳遞是一個元組,包含分割對象的字符串,其實質就是將Python默認的(‘, ’,': ')分隔符替換成(',',':')。
    data = {'b':789,'c':456,'a':123}   
    print 'DATA:', repr(data)   
    print 'repr(data)             :', len(repr(data))   
    print 'dumps(data)            :', len(json.dumps(data))   
    print 'dumps(data, indent=2)  :', len(json.dumps(data, indent=4))   
    print 'dumps(data, separators):', len(json.dumps(data, separators=(',',':')))  

輸出:

    DATA: {'a': 123, 'c': 456, 'b': 789}   
    repr(data)             : 30   
    dumps(data)            : 30   
    dumps(data, indent=2)  : 46   
    dumps(data, separators): 25  


另一個比較有用的dumps參數是skipkeys,默認為False。 dumps方法存儲dict對象時key必須是str類型,其他類型會導致TypeError異常產生,如果將skipkeys設為True則會優雅的濾除非法keys。

    data = {'b':789,'c':456,(1,2):123}   
    print'original data:',repr(data)   
    print 'json encoded',json.dumps(data,skipkeys=True)  

輸出:

     original data: {(1, 2): 123, 'c': 456, 'b': 789}   
    json encoded {"c": 456, "b": 789}  

2,JSON處理自定義數據類型

json模塊不僅可以處理普通的python內置類型,也可以處理我們自定義的數據類型,而往往處理自定義的對象是很常用的。

如果直接通過json.dumps方法對Person的實例進行處理的話,會報錯,因為json無法支持這樣的自動轉化。通過上面所提到的json和 python的類型轉化對照表,可以發現,object類型是和dict相關聯的,所以我們需要把我們自定義的類型轉化為dict,然后再進行處理。這里,有兩種方法可以使用。

方法一:自己寫轉化函數

自定義object類型和dict類型進行轉化:encode-定義函數 object2dict()將對象模塊名、類名以及__dict__存儲在一個字典并返回;decode-定義dict2object()解析出模塊名、類名、參數,創建新的對象并返回。在json.dumps()中通過default參數指定轉化過程中調用的函數;json.loads()則通過 object_hook指定轉化函數。

方法二:繼承JSONEncoder和JSONDecoder類,覆寫相關方法

JSONEncoder類負責編碼,主要是通過其default函數進行轉化,我們可以重載該方法。對于JSONDecoder,亦然。

    #handling private data type   
    #define class   
    class Person(object):   
        def __init__(self,name,age):   
            self.name = name   
            self.age = age   
        def __repr__(self):   
            return 'Person Object name : %s , age : %d' % (self.name,self.age)   


    #define transfer functions   
    def object2dict(obj):   
        #convert object to a dict   
        d = {'__class__':obj.__class__.__name__, '__module__':obj.__module__}   
        d.update(obj.__dict__)   
        return d   

    def dict2object(d):   
        #convert dict to object   
        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)   
            inst = class_(**args) #create new instance   
        else:   
            inst = d   
        return inst   
    #recreate the default method   
    class LocalEncoder(json.JSONEncoder):   
        def default(self,obj):   
            #convert object to a dict   
            d = {'__class__':obj.__class__.__name__, '__module__':obj.__module__}   
            d.update(obj.__dict__)   
            return d   

    class LocalDecoder(json.JSONDecoder):   
        def __init__(self):   
            json.JSONDecoder.__init__(self,object_hook = self.dict2object)   
        def dict2object(self, d):   
            #convert dict to object   
            if'__class__' in d:   
                class_name = d.pop('__class__')   
                module_name = d.pop('__module__')   
                module = __import__(module_name)   
                class_ = getattr(module,class_name)   
                args = dict((key.encode('ascii'), value) for key, value in d.items()) #get args  
                inst = class_(**args) #create new instance  
            else:   
                inst = d   
            return inst   
    #test function   
    if __name__  == '__main__':   
        p = Person('Aidan',22)   
        print p   
        #json.dumps(p)#error will be throwed   
        d = object2dict(p)   
        print 'method-json encode:', d   

        o = dict2object(d)   
        print 'the decoded obj type: %s, obj:%s' % (type(o),repr(o))   

        dump = json.dumps(p,default=object2dict)   
        print 'dumps(default = object2dict):',dump   
        load = json.loads(dump,object_hook = dict2object)   
        print 'loads(object_hook = dict2object):',load   
        d = LocalEncoder().encode(p)   
        o =  LocalDecoder().decode(d)   

        print 'recereated encode method: ',d   
        print 'recereated decode method: ',type(o),o  

輸出:

Person Object name : Aidan , age : 22   
method-json encode: {'age': 22, '__module__': '__main__', '__class__': 'Person', 'name': 'Aidan'}   
the module is: <module '__main__' from 'D:/Project/Python/study_json'>   
the atrribute: {'age': 22, 'name': 'Aidan'}   
the decoded obj type: <class '__main__.Person'>, obj:Person Object name : Aidan , age : 22   
dumps(default = object2dict): {"age": 22, "__module__": "__main__", "__class__": "Person", "name": "Aidan"}   
the module is: <module '__main__' from 'D:/Project/Python/study_json'>   
the atrribute: {'age': 22, 'name': u'Aidan'}   
loads(object_hook = dict2object): Person Object name : Aidan , age : 22   
recereated encode method:  {"age": 22, "__module__": "__main__", "__class__": "Person", "name": "Aidan"}   
recereated decode method:  <class '__main__.Person'> Person Object name : Aidan , age : 22 

來自:http://blog.csdn.net/suipingsp/article/details/39480341

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!