1. 程式人生 > >python Json的一點收穫,自定義序列化方法

python Json的一點收穫,自定義序列化方法

PyMOTW: json

  • 模組: json
  • 目的: JavaScript物件格式序列器
  • python版本: 2.6

json模組提供了一個類似於pickle中用於轉換記憶體中python物件為一個序列表示形式(“JavaScript Object Notation”)的API介面. 但和pickle不同的是, JSON在其他很多語言中都有對應實現(特別是在JavaScript中), 使其更適用於內部應用間的通訊. 在一個AJAX應用中, JSON可能對於web伺服器和客戶端間的通訊, 使用最為廣泛, 但它也不僅限於這類應用.

簡單資料型別的編碼和解碼

編碼器預設支援Python的本地型別(如int, float, list, tuple, dict).

 

編碼器處理之後的值和Python的repr()的輸出值很類似.

 

編碼之後的解碼所獲的的值可能和原先的物件不是完全一致.

 

比如說, 元組會被轉換為JSON的列表.

 

人性化使用 vs 緊湊型輸出

JSON優於pickle的另外一點是其結果具有可讀性. dumps()函式接收多個引數用於更好的輸出結構. 比如說. sort_keys引數告訴編碼器按照順序輸出字典的鍵值, 而不是隨機無序的.

 

排序之後更容易讓人看出結果, 也使進行JSON的比較輸出成為可能.

 

對於高度巢狀的資料結構, 你會想在輸出結果中增加縮排以更好的顯示其格式.

 

當indent引數是一非負整數時, 輸出的結構和pprint更為接近, 在每個縮排層次上都有前導空格.

 

像這種型別輸出的資料在傳輸過程中需佔用更多的位元組, 不過, 在實際生產環境中沒有必要使用縮排格式. 實際上, 你可以設定資料的分隔符來讓結果更為緊湊.

 

dumps()函式的separators引數是一個元組, 包含分隔列表各項和字典鍵值各項的字串. 預設是(‘, ‘, ‘: ‘). 可以去掉後者中的空格, 我們可以得到較緊湊的輸出.

 

編碼字典

JSON格式中, 字典的鍵被限制為字串型別. 如果字典中的鍵是其他型別, 那麼在編碼這個物件時會產生一個TypeError異常. 一種解決這個限制的方法是, 在編碼時, 使用skipkeys引數跳過所有非字串型別的鍵.

 

非字串型別的鍵被忽略, 而不丟擲一個異常.

 

自定義型別的處理

上面所有的例子都是用了Python的內建型別作為例子, 因為他們都被json本身支援. 當然, 自定義型別也常常需要正確編碼. 這裡有兩種情況:

第一, 對於一個類的編碼:

 

編碼一個MyObj物件的最簡單方式是定義個轉換函式, 用於將位置型別轉換出呢個已知型別. 你沒有必要自己進行編碼, 而僅需要將一個物件轉換成另一個物件.

 

在convert_to_builtin_type()函式中, 不被json識別的類物件被轉換成一個包含足夠能重建這個物件的字典資訊.

 

為了能解碼結果資料並建立一個MyObj例項, 我們需要配合解碼器以便可以從模組中匯入類並建立例項. 我們在loads()函式中使用object_hook引數.

在輸入資料流中, 對於解碼獲得的每個字典都會呼叫object_hook, 將這個字典轉換成其他型別的物件. hook函式返回的是呼叫程式所需要的物件, 而不是字典.

 

由於json將字串值轉換成unicode物件, 所以我們需要將作為類構造器的引數重新編碼為ASCII字串.

 

對於內建型別也都有類似的hooks, 如整型(parse_int), 浮點型(parse_float), 常量(parse_constant).

編碼和解碼類

除了上述的這些函式外, json模組還提供了編碼和解碼類. 直接使用這些類, 你可以訪問到額外的API介面或者定製建立它的子類.

JSONEncoder提供了一個產生編碼資料”塊”的的迭代介面, 這在寫入一個檔案或網路sockets時(不需要在記憶體中完整表示整個資料)是非常方便的,

 

正如你看到的, 資料是以邏輯單位形式輸出的, 而不是按照資料長度輸出.

 

encode()方法基本上等價於’‘.join(encoder.iterencode()), 只是多了些附加錯誤檢查.

為了能夠編碼任何型別的物件, 我們可以編寫一類似於上述的convert_to_builtin_type()函式去過載default()方法.

 

這裡輸出的結果是和先前的實現一致的.

 

解碼後將字典轉換成一個物件, 在先前實現的基礎上稍作修改即可.

 

輸出結果也是和先前例子中輸出的一樣.

 

流和檔案的處理

到目前為止的所有例子, 我們都假設待編碼的資料都是一次性完整載入到記憶體中的. 但對於大型資料結構來說, 將編碼資料直接寫入一個類檔案物件, 可能會更好. load()和dump()函式可以接收一個用於讀或寫的類檔案物件的引用.

 

對於socket來說, 也和正常檔案控制代碼類似.

 

雖然一次性讀取部分資料不是很好, 但是load()函式仍然提供了從流資料輸入中封裝生成物件的功能.

 

 

混合資料流

JSONDecoder包含了raw_decode()方法, 用於解碼在很多資料組成的資料結構, 例如包含多餘文字的JSON資料. 返回的值是從輸入資料中解碼獲得的物件, 資料中的index表示解碼物件結束時所在的位置.

 

不幸的是, 這僅僅在物件出現在輸入流的開始處才有效.