From: http://blog.csdn.net/jlnuboy/article/details/5732196
PyMOTW: json
- 模塊: json
- 目的: JavaScript對象格式序列器
- python版本: 2.6
json模塊提供了一個類似于pickle中用于轉(zhuǎn)換內(nèi)存中python對象為一個序列表示形式(“JavaScript Object Notation”)的API接口. 但和pickle不同的是, JSON在其他很多語言中都有對應(yīng)實現(xiàn)(特別是在JavaScript中), 使其更適用于內(nèi)部應(yīng)用間的通信. 在一個AJAX應(yīng)用中, JSON可能對于web服務(wù)器和客戶端間的通信, 使用最為廣泛, 但它也不僅限于這類應(yīng)用.
?
?
?
簡單數(shù)據(jù)類型的編碼和解碼
編碼器默認支持Python的本地類型(如int, float, list, tuple, dict).
?
?
[python] view plaincopy
import?json??data?=?[?{?'a':'A',?'b':(2,?4),?'c':3.0?}?]??print?'DATA:',?repr(data)??data_string?=?json.dumps(data)??print?'JSON:',?data_string??
?
編碼器處理之后的值和Python的repr()的輸出值很類似.
[python] view plaincopy
$?python?json_simple_types.py??DATA:?[{'a':?'A',?'c':?3.0,?'b':?(2,?4)}]??JSON:?[{"a":?"A",?"c":?3.0,?"b":?[2,?4]}]??
?
編碼之后的解碼所獲的的值可能和原先的對象不是完全一致.
[python] view plaincopy
import?json??data?=?[?{?'a':'A',?'b':(2,?4),?'c':3.0?}?]??data_string?=?json.dumps(data)??print?'ENCODED:',?data_string??decoded?=?json.loads(data_string)??print?'DECODED:',?decoded??print?'ORIGINAL:',?type(data[0]['b'])??print?'DECODED?:',?type(decoded[0]['b'])??
?
比如說, 元組會被轉(zhuǎn)換為JSON的列表.
[python] view plaincopy
$?python?json_simple_types_decode.py??ENCODED:?[{"a":?"A",?"c":?3.0,?"b":?[2,?4]}]??DECODED:?[{u'a':?u'A',?u'c':?3.0,?u'b':?[2,?4]}]??ORIGINAL:?<type?'tuple'>??DECODED?:?<type?'list'>??
?
?
人性化使用 vs 緊湊型輸出
JSON優(yōu)于pickle的另外一點是其結(jié)果具有可讀性. dumps()函數(shù)接收多個參數(shù)用于更好的輸出結(jié)構(gòu). 比如說. sort_keys參數(shù)告訴編碼器按照順序輸出字典的鍵值, 而不是隨機無序的.
[python] view plaincopy
import?json??data?=?[?{?'a':'A',?'b':(2,?4),?'c':3.0?}?]??print?'DATA:',?repr(data)??unsorted?=?json.dumps(data)??print?'JSON:',?json.dumps(data)??print?'SORT:',?json.dumps(data,?sort_keys=True)??first?=?json.dumps(data,?sort_keys=True)??second?=?json.dumps(data,?sort_keys=True)??print?'UNSORTED?MATCH:',?unsorted?==?first??print?'SORTED?MATCH?:',?first?==?second??
?
排序之后更容易讓人看出結(jié)果, 也使進行JSON的比較輸出成為可能.
?
[python] view plaincopy
$?python?json_sort_keys.py??DATA:?[{'a':?'A',?'c':?3.0,?'b':?(2,?4)}]??JSON:?[{"a":?"A",?"c":?3.0,?"b":?[2,?4]}]??SORT:?[{"a":?"A",?"b":?[2,?4],?"c":?3.0}]??UNSORTED?MATCH:?False??SORTED?MATCH?:?True??
?
對于高度嵌套的數(shù)據(jù)結(jié)構(gòu), 你會想在輸出結(jié)果中增加縮進以更好的顯示其格式.
[python] view plaincopy
import?json??data?=?[?{?'a':'A',?'b':(2,?4),?'c':3.0?}?]??print?'DATA:',?repr(data)??print?'NORMAL:',?json.dumps(data,?sort_keys=True)??print?'INDENT:',?json.dumps(data,?sort_keys=True,?indent=2)??
?
當indent參數(shù)是一非負整數(shù)時, 輸出的結(jié)構(gòu)和pprint更為接近, 在每個縮進層次上都有前導(dǎo)空格.
[python] view plaincopy
$?python?json_indent.py??DATA:?[{'a':?'A',?'c':?3.0,?'b':?(2,?4)}]??NORMAL:?[{"a":?"A",?"b":?[2,?4],?"c":?3.0}]??INDENT:?[???????????????{???????????????"a":?"A",???????????????"b":?[????????????????????????2,????????????????????????4????????????????????????],???????????????"c":?3.0???????????????}??]??
?
像這種類型輸出的數(shù)據(jù)在傳輸過程中需占用更多的字節(jié), 不過, 在實際生產(chǎn)環(huán)境中沒有必要使用縮進格式. 實際上, 你可以設(shè)置數(shù)據(jù)的分隔符來讓結(jié)果更為緊湊.
[python] view plaincopy
import?json??data?=?[?{?'a':'A',?'b':(2,?4),?'c':3.0?}?]??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=2))??print?'dumps(data,?separators):',?len(json.dumps(data,?separators=(',',':')))??
?
dumps()函數(shù)的separators參數(shù)是一個元組, 包含分隔列表各項和字典鍵值各項的字符串. 默認是(‘, ‘, ‘: ‘). 可以去掉后者中的空格, 我們可以得到較緊湊的輸出.
[python] view plaincopy
$?python?json_compact_encoding.py??DATA:?[{'a':?'A',?'c':?3.0,?'b':?(2,?4)}]??repr(data)?:?35??dumps(data)?:?35??dumps(data,?indent=2)?:?76??dumps(data,?separators):?29??
?
?
編碼字典
JSON格式中, 字典的鍵被限制為字符串類型. 如果字典中的鍵是其他類型, 那么在編碼這個對象時會產(chǎn)生一個TypeError異常. 一種解決這個限制的方法是, 在編碼時, 使用skipkeys參數(shù)跳過所有非字符串類型的鍵.
[python] view plaincopy
import?json??data?=?[?{?'a':'A',?'b':(2,?4),?'c':3.0,?('d',):'D?tuple'?}?]??print?'First?attempt'??try:??????print?json.dumps(data)??except?TypeError,?err:??????print?'ERROR:',?err??print??print?'Second?attempt'??print?json.dumps(data,?skipkeys=True)??
?
非字符串類型的鍵被忽略, 而不拋出一個異常.
[python] view plaincopy
$?python?json_skipkeys.py??First?attempt??ERROR:?key?('d',)?is?not?a?string??Second?attempt??[{"a":?"A",?"c":?3.0,?"b":?[2,?4]}]??
?
?
自定義類型的處理
上面所有的例子都是用了Python的內(nèi)置類型作為例子, 因為他們都被json本身支持. 當然, 自定義類型也常常需要正確編碼. 這里有兩種情況:
第一, 對于一個類的編碼:
[python] view plaincopy
class?MyObj(object):??????def?__init__(self,?s):??????????self.s?=?s??????def?__repr__(self):??????????return?'<MyObj(%s)>'?%?self.s??
?
編碼一個MyObj對象的最簡單方式是定義個轉(zhuǎn)換函數(shù), 用于將位置類型轉(zhuǎn)換出呢個已知類型. 你沒有必要自己進行編碼, 而僅需要將一個對象轉(zhuǎn)換成另一個對象.
[python] view plaincopy
import?json??import?json_myobj??obj?=?json_myobj.MyObj('instance?value?goes?here')??print?'First?attempt'??try:??????print?json.dumps(obj)??except?TypeError,?err:??????print?'ERROR:',?err??def?convert_to_builtin_type(obj):??????print?'default(',?repr(obj),?')'????????????d?=?{?'__class__':obj.__class__.__name__,????????????'__module__':obj.__module__,??????????}??????d.update(obj.__dict__)??????return?d??print??print?'With?default'??print?json.dumps(obj,?default=convert_to_builtin_type)??
?
在convert_to_builtin_type()函數(shù)中, 不被json識別的類對象被轉(zhuǎn)換成一個包含足夠能重建這個對象的字典信息.
[python] view plaincopy
$?python?json_dump_default.py??First?attempt??ERROR:?<MyObj(instance?value?goes?here)>?is?not?JSON?serializable??With?default??default(?<MyObj(instance?value?goes?here)>?)??{"s":?"instance?value?goes?here",?"__module__":?"json_myobj",?"__class__":?"MyObj"}??
?
?
為了能解碼結(jié)果數(shù)據(jù)并創(chuàng)建一個MyObj實例, 我們需要配合解碼器以便可以從模塊中導(dǎo)入類并創(chuàng)建實例. 我們在loads()函數(shù)中使用object_hook參數(shù).
在輸入數(shù)據(jù)流中, 對于解碼獲得的每個字典都會調(diào)用object_hook, 將這個字典轉(zhuǎn)換成其他類型的對象. hook函數(shù)返回的是調(diào)用程序所需要的對象, 而不是字典.
[python] view plaincopy
import?json??def?dict_to_object(d):??????if?'__class__'?in?d:??????????class_name?=?d.pop('__class__')??????????module_name?=?d.pop('__module__')??????????module?=?__import__(module_name)??????????print?'MODULE:',?module??????????class_?=?getattr(module,?class_name)??????????print?'CLASS:',?class_??????????args?=?dict(?(key.encode('ascii'),?value)?for?key,?value?in?d.items())??????????print?'INSTANCE?ARGS:',?args??????????inst?=?class_(**args)??????else:??????????inst?=?d??????return?inst??encoded_object?=?'[{"s":?"instance?value?goes?here",?"__module__":?"json_myobj",?"__class__":?"MyObj"}]'??myobj_instance?=?json.loads(encoded_object,?object_hook=dict_to_object)??print?myobj_instance??
?
由于json將字符串值轉(zhuǎn)換成unicode對象, 所以我們需要將作為類構(gòu)造器的參數(shù)重新編碼為ASCII字符串.
[python] view plaincopy
$?python?json_load_object_hook.py??MODULE:?<module?'json_myobj'?from?'/Users/dhellmann/Documents/PyMOTW/src/PyMOTW/json/json_myobj.pyc'>??CLASS:?<class?'json_myobj.MyObj'>??INSTANCE?ARGS:?{'s':?u'instance?value?goes?here'}??[<MyObj(instance?value?goes?here)>]??
?
?
對于內(nèi)置類型也都有類似的hooks, 如整型(parse_int), 浮點型(parse_float), 常量(parse_constant).
編碼和解碼類
除了上述的這些函數(shù)外, json模塊還提供了編碼和解碼類. 直接使用這些類, 你可以訪問到額外的API接口或者定制創(chuàng)建它的子類.
JSONEncoder提供了一個產(chǎn)生編碼數(shù)據(jù)”塊”的的迭代接口, 這在寫入一個文件或網(wǎng)絡(luò)sockets時(不需要在內(nèi)存中完整表示整個數(shù)據(jù))是非常方便的,
[python] view plaincopy
import?json??encoder?=?json.JSONEncoder()??data?=?[?{?'a':'A',?'b':(2,?4),?'c':3.0?}?]??for?part?in?encoder.iterencode(data):??????print?'PART:',?part?? ?
正如你看到的, 數(shù)據(jù)是以邏輯單位形式輸出的, 而不是按照數(shù)據(jù)長度輸出.
[python] view plaincopy
$?python?json_encoder_iterable.py???????PART:?[???????????????PART:?{???????????????PART:?"a"???????????????PART:?:???????????????PART:?"A"???????????????PART:?,???????????????PART:?"c"???????????????PART:?:???????????????PART:?3.0???????????????PART:?,???????????????PART:?"b"???????????????PART:?:???????????????PART:?[???????????????PART:?2???????????????PART:?,???????????????PART:?4???????????????PART:?]???????????????PART:?}???????????????PART:?]?? ?
?
encode()方法基本上等價于’‘.join(encoder.iterencode()), 只是多了些附加錯誤檢查.
為了能夠編碼任何類型的對象, 我們可以編寫一類似于上述的convert_to_builtin_type()函數(shù)去重載default()方法.
[python] view plaincopy
import?json??import?json_myobj??class?MyEncoder(json.JSONEncoder):??????def?default(self,?obj):??????????print?'default(',?repr(obj),?')'????????????????????d?=?{?'__class__':obj.__class__.__name__,????????????????'__module__':obj.__module__,??????????????}??????????d.update(obj.__dict__)??????????return?d??obj?=?json_myobj.MyObj('internal?data')??print?obj??print?MyEncoder().encode(obj)?? ?
這里輸出的結(jié)果是和先前的實現(xiàn)一致的.
[python] view plaincopy
$?python?json_encoder_default.py??<MyObj(internal?data)>??default(?<MyObj(internal?data)>?)??{"s":?"internal?data",?"__module__":?"json_myobj",?"__class__":?"MyObj"}?? ?
解碼后將字典轉(zhuǎn)換成一個對象, 在先前實現(xiàn)的基礎(chǔ)上稍作修改即可.
[python] view plaincopy
import?json??class?MyDecoder(json.JSONDecoder):??????def?__init__(self):??????????json.JSONDecoder.__init__(self,?object_hook=self.dict_to_object)??????def?dict_to_object(self,?d):??????????if?'__class__'?in?d:??????????????class_name?=?d.pop('__class__')??????????????module_name?=?d.pop('__module__')??????????????module?=?__import__(module_name)??????????????print?'MODULE:',?module??????????????class_?=?getattr(module,?class_name)??????????????print?'CLASS:',?class_??????????????args?=?dict(?(key.encode('ascii'),?value)?for?key,?value?in?d.items())??????????????print?'INSTANCE?ARGS:',?args??????????????inst?=?class_(**args)??????????else:??????????????inst?=?d??????????return?inst??encoded_object?=?'[{"s":?"instance?value?goes?here",?"__module__":?"json_myobj",?"__class__":?"MyObj"}]'??myobj_instance?=?MyDecoder().decode(encoded_object)??print?myobj_instance?? ?
輸出結(jié)果也是和先前例子中輸出的一樣.
[python] view plaincopy
$?python?json_decoder_object_hook.py??MODULE:?<module?'json_myobj'?from?'/Users/dhellmann/Documents/PyMOTW/src/PyMOTW/json/json_myobj.pyc'>??CLASS:?<class?'json_myobj.MyObj'>??INSTANCE?ARGS:?{'s':?u'instance?value?goes?here'}??[<MyObj(instance?value?goes?here)>]?? ?
?
流和文件的處理
到目前為止的所有例子, 我們都假設(shè)待編碼的數(shù)據(jù)都是一次性完整加載到內(nèi)存中的. 但對于大型數(shù)據(jù)結(jié)構(gòu)來說, 將編碼數(shù)據(jù)直接寫入一個類文件對象, 可能會更好. load()和dump()函數(shù)可以接收一個用于讀或?qū)懙念愇募ο蟮囊?
[python] view plaincopy
import?json??import?tempfile??data?=?[?{?'a':'A',?'b':(2,?4),?'c':3.0?}?]??f?=?tempfile.NamedTemporaryFile(mode='w+')??json.dump(data,?f)??f.flush()??print?open(f.name,?'r').read()?? ?
對于socket來說, 也和正常文件句柄類似.
[python] view plaincopy
$?python?json_dump_file.py??[{"a":?"A",?"c":?3.0,?"b":?[2,?4]}]?? ?
雖然一次性讀取部分數(shù)據(jù)不是很好, 但是load()函數(shù)仍然提供了從流數(shù)據(jù)輸入中封裝生成對象的功能.
[python] view plaincopy
import?json??import?tempfile??f?=?tempfile.NamedTemporaryFile(mode='w+')??f.write('[{"a":?"A",?"c":?3.0,?"b":?[2,?4]}]')??f.flush()??f.seek(0)??print?json.load(f)?? ?
[python] view plaincopy
$?python?json_load_file.py??[{u'a':?u'A',?u'c':?3.0,?u'b':?[2,?4]}]?? ?
?
混合數(shù)據(jù)流
JSONDecoder包含了raw_decode()方法, 用于解碼在很多數(shù)據(jù)組成的數(shù)據(jù)結(jié)構(gòu), 例如包含多余文本的JSON數(shù)據(jù). 返回的值是從輸入數(shù)據(jù)中解碼獲得的對象, 數(shù)據(jù)中的index表示解碼對象結(jié)束時所在的位置.
[python] view plaincopy
import?json??decoder?=?json.JSONDecoder()??def?get_decoded_and_remainder(input_data):??????obj,?end?=?decoder.raw_decode(input_data)??????remaining?=?input_data[end:]??????return?(obj,?end,?remaining)??encoded_object?=?'[{"a":?"A",?"c":?3.0,?"b":?[2,?4]}]'??extra_text?=?'This?text?is?not?JSON.'??print?'JSON?first:'??obj,?end,?remaining?=?get_decoded_and_remainder('?'.join([encoded_object,?extra_text]))??print?'Object?:',?obj??print?'End?of?parsed?input?:',?end??print?'Remaining?text?:',?repr(remaining)??print??print?'JSON?embedded:'??try:??????obj,?end,?remaining?=?get_decoded_and_remainder(???????????????????'?'.join([extra_text,?encoded_object,?extra_text])???????????????????)??except?ValueError,?err:??????print?'ERROR:',?err?? ?
不幸的是, 這僅僅在對象出現(xiàn)在輸入流的開始處才有效.
[python] view plaincopy
$?python?json_mixed_data.py??JSON?first:??Object?:?[{u'a':?u'A',?u'c':?3.0,?u'b':?[2,?4]}]??End?of?parsed?input?:?35??Remaining?text?:?'?This?text?is?not?JSON.'??JSON?embedded:??ERROR:?No?JSON?object?could?be?decoded??
總結(jié)
以上是生活随笔為你收集整理的python Json的一点收获,自定义序列化方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。