上一節咱們學習了文件的讀寫,把一個字符串(或字節對象)保存到磁盤是一件很容易的事情。可是在實際編程中,咱們常常須要保存結構化數據,好比複雜的字典、嵌套的列表等等,這時候就須要咱們想辦法把這些結構化數據先轉變成一個字符串,這個轉換過程就叫作「序列化」,這一過程的逆操做就是「反序列化」。程序員
序列化數據的操做在各個語言編程中都會遇到,固然也出現了標準化的格式,好比:JSON(JavaScript Object Notation)。JSON格式一般被現代應用程序用於數據交換,尤爲是在Web中廣爲人知,是許多程序員的選擇。Python支持JSON的模塊叫作json
。編程
JSON的數據格式和Python中的字典和列表很是類似,能夠說它是字典和列表相互嵌套的結合體,而這些字典和列表的基本數據類型只能是:字符串、整數、浮點數、布爾型、None,不能是自定義的類等複雜對象。json
一個對象x
能夠用一行簡單的代碼轉換成它對應的JSON字符串:安全
In [124]: import json In [125]: json.dumps({'Tom': 23, 'Jim': 25, 'William': 21}) Out[125]: '{"Tom": 23, "Jim": 25, "William": 21}'
把JSON字符串反序列化爲Python對象的代碼也只有一行:函數
In [126]: json.loads('{"Tom": 23, "Jim": 25, "William": 21}') Out[126]: {'Tom': 23, 'Jim': 25, 'William': 21}
dumps()
方法有個變體叫作dump()
,它是將對象序列化到文件中。若是f
是一個文件對象,咱們能夠這樣操做:工具
json.dump(x, f)
對應的,從文件對象f
中反序列化的操做就是:學習
x = json.load(f)
dumps()
函數有不少參數可選,使咱們生成不一樣格式的JSON字符串,具體能夠在IPython中經過json.dumps?
來查看。咱們能夠經過下面的例子來了解一下:編碼
(1)緊湊編碼
經過separators
參數來實現:spa
In [130]: json.dumps({"Tom": 23, "Jim": 25, "William": 21}, separators=(',', ':')) Out[130]: '{"Tom":23,"Jim":25,"William":21}'
(2)美化輸出
經過sort_keys, indent
參數來實現:設計
In [132]: print(json.dumps({"Tom": 23, "Jim": 25, '9':3, '3': 10}, sort_keys=True, indent=4)) { "3": 10, "9": 3, "Jim": 25, "Tom": 23 }
(3)中文編碼
參數ensure_ascii
默認爲True,會把中文等非ascii字符轉義:
In [133]: print(json.dumps({"小剛": 23, "小明": 25, '9':3, '3': 10}, sort_keys=True, indent=4)) { "3": 10, "9": 3, "\u5c0f\u521a": 23, "\u5c0f\u660e": 25 } In [134]: print(json.dumps({"小剛": 23, "小明": 25, '9':3, '3': 10}, sort_keys=True, indent=4, ensure_ascii=False)) { "3": 10, "9": 3, "小剛": 23, "小明": 25 }
與json
模塊不一樣,pickle
能夠對任意複雜的Python對象進行序列化,它是Python特有的,不能與其它語言進行通訊。默認狀況下,它也是不安全的,若是數據是由黑客精心設計的,則反序列化的數據可能被植入惡意代碼。
pickle
的接口跟json
是同樣的,序列化用dumps(x), dump(x, f)
,反序列化使用loads(s), load(f)
。可是,pickle
能夠序列化任意複雜的對象,好比自定義的類、函數都是能夠用它來序列化的。好比下面這個例子就是序列化b並反序列化一個函數:
In [136]: def add(x, y): ...: print(x+y) ...: In [137]: import pickle In [138]: s = pickle.dumps(add) In [139]: s Out[139]: b'\x80\x03c__main__\nadd\nq\x00.' In [140]: f = pickle.loads(s) In [141]: f Out[141]: <function __main__.add(x, y)> In [142]: f(2, 3) 5
從這個例子中,咱們實現了序列化和反序列化一個函數的功能。這樣,咱們能夠把一些函數、自定義的類等各類對象先序列化到文件,而後把這個文件發給別人,別人能夠經過反序列化來使用這些自定義的類和函數。這個過程當中,若是有人對序列化文件作了手腳,好比經過修改文件修改了函數add()
的實現,就有可能被黑客利用來進行攻擊。這也是前面咱們爲何說pickle
默認是不安全的。因此,在選擇是否使用它進行序列化時,要先思考一番。
Python爲咱們提供了數據序列化的工具。若是須要和其它程序進行數據交換,json是最好的選擇。若是是本身內部使用,pickle能夠做爲一個選擇進行復雜對象的序列化。