Python的序列化与反序列化
序列化和反序列化可以大致分為兩類:文本序列化和二進制序列化。比如python提供的pickle庫,他就是基于二進制方式的序列化。而json則是文本方式的序列化,需要遵守相應的文件格式。
由于pickle序列化和發序列化僅僅同版本的Python可以使用(pickle庫的序列化在python2,python3也存在不兼容的問題)。因此我們還會學習MessagePack,它是一個基于二進制高效的對象序列化類庫,可用于跨語言通信。
一.序列化概述
1.為什么要序列化
內存中的字典,列表,集合以及各種對象,如何保存到一個文件中?
如果是自己定義的類的實例,如何保存到一個文件中?
如何從文件中讀取數據,并讓他在內存中再次恢復成自己對應的類的實例?
要設計一套協議,按照某種規則,把內存這種數據保存到文件中。文件是一個字節序列,所以必須把數據轉換成字節序列,輸出到文件。這就是序列化。
反之,從文件的字節序列恢復到內存并且還要原來的類型,就是反序列化。
2. 序列化相關術語
serialization 將內存中對象存儲下來,把它變成一個個字節。deserialization 將文件的一個個字節恢復成內存中對象。序列化保存到文件就是持久化。
可以將數據序列化后持久化,或者網絡傳輸;也可以將從文件中或者網絡接受到的字節序列反序列化。Python提供了pickle庫,它是一種基于二進制方式的序列化。
3.序列化應用
一般來說,本地序列化的情況,應用較少。大多數場景都應用在網絡傳輸中。
將數據序列化后通過網絡傳輸到遠程節點,遠程服務器上的服務將接收的數據反序列化后,就可以使用了。
但是,要注意一點,遠程接收端,反序列化時必須有對應的數據類型,否則就會報錯。尤其是自定義類,必須遠程得有一致的定義。
現在,大多數項目,都不是單機的,也不是單服務的,需要多個程序之間配合。需要通過網絡將數據傳送到其它節點上去,這就需要大量的序列化,反序列化過程。
但是,問題是Python程序之間可以使用pickle解決序列化,反序列化,,如果是跨平臺,跨語言,跨協議pickle就不太適合了,就需要公共的協議。例如XML,JSON,PROTOCOL BUFFER等。
不同的協議,效率不同,學習曲線不同,適用不同場景,要根據不同的情況分析選型。
二.pikcle模塊
1.方法說明
dumps:對象序列化為bytes對象,一般用于處理網絡傳輸的數據。dump:對象序列化到文件對象,比如存入本地文件。loads:從bytes對象反序列化,一般用于處理網絡接受的數據。load:對象發序列化,從文件讀取數據。2.序列化和反序列化基礎數據類型
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' #!/usr/bin/env python #_*_conding:utf-8_*_ import picklefile_name = r"E:\temp\test\ser.txt"s1 = 99 s2 = 'c' s3 = list("123") s4 = {"a":1,"b":"abc","c":[1,2,3]}#序列化 with open(file_name,"wb") as f:pickle.dump(s1,f)pickle.dump(s2,f)pickle.dump(s3,f)pickle.dump(s4,f)#反序列化 with open(file_name,"rb") as f:print(f.read(),f.seek(0))for i in range(4):x = pickle.load(f)print(x,type(x))#以上代碼執行結果如下: b'\x80\x03Kc.\x80\x03X\x01\x00\x00\x00cq\x00.\x80\x03]q\x00(X\x01\x00\x00\x001q\x01X\x01\x00\x00\x002q\x02X\x01\x00\x00\x003q\x03e.\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01K\x01X\x01\x00\x00\x00bq\x02X\x03\x00\x00\x00abcq\x03X\x01\x00\x00\x00cq\x04]q\x05(K\x01K\x02K\x03eu.' 0 99 <class 'int'> c <class 'str'> ['1', '2', '3'] <class 'list'> {'a': 1, 'b': 'abc', 'c': [1, 2, 3]} <class 'dict'>3.序列化和反序列化對象
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' #!/usr/bin/env python #_*_conding:utf-8_*_ import picklefile_name = r"E:\temp\test\ser.txt"#定義對象 class Person:def __init__(self,name,age=18):self.__name = nameself.__age = age@propertydef name(self):return self.__name@name.setterdef name(self,name):self.__name = namedef getage(self):return self.__agedef setage(self,age):self.__age = ageage = property(fget=getage,fset=setage,doc="age property")def __repr__(self):return "{} 今年已經 {} 歲啦!".format(self.__name,self.__age)p1 = Person("Yinzhengjie",20)p1.age = 27#序列化 ser = pickle.dumps(p1) print("ser = {}".format(ser))#反序列化 p2 = pickle.loads(ser) print(type(p2)) print(p2)#以上代碼執行結果如下: ser = b'\x80\x03c__main__\nPerson\nq\x00)\x81q\x01}q\x02(X\r\x00\x00\x00_Person__nameq\x03X\x0b\x00\x00\x00Yinzhengjieq\x04X\x0c\x00\x00\x00_Person__ageq\x05K\x1bub.' <class '__main__.Person'> Yinzhengjie 今年已經 27 歲啦!三.json模塊
1.Json概述
JSON(JavaScript Object Notation,JS對象標記)是一種輕量級的數據交換格式。它基于ECMAScript(w3c組織制定的JS規范)的一個子集,采用完全獨立與編程語言的文本格式來存儲和表示數據。
一般來說,json編碼的數據很少落地,數據都是通過網絡傳輸,傳輸的時候,需考慮壓縮它。本質上來說它就是個文本,就是個字符串。
json很簡單,幾乎所有編程都支持Json,所以應用范圍十分廣泛。
官方網址請參考:http://json.org/。
2.Json數據類型
值:
雙引號引起來的字符串,數值,true和false,null,對象,數組,這些都是值。
字符串:
由雙引號包圍起來的任意字符的組合,可以有轉義字符。
數值:
有正負,有整數,浮點數。
對象:
無序的鍵值對的集合。
格式:{key1:value1,…keyn:valulen}
key必須是一個字符串,需要雙引號包圍這個字符串。
value可以是任意合法的值。
數組:
有序的值和集合。
格式:[val1,…valn]
案例如下:
{"person":[{"name":"jason","age":18},{"name":"yinzhengjie""age":16}],"total":2 }3.Python與Json
Python支持少量內建數據類型到Json類型的轉換,大致如下:
| True | true |
| False | false |
| None | null |
| str | string |
| int | integer |
| float | float |
| list | array |
| dict | object |
4.json模塊應用案例
#!/usr/bin/env python #_*_conding:utf-8_*_import jsonsrc = {'name':'Jason','age':20,'interest':('music','movie'),'class':['python']}json_ser = json.dumps(src) #進行json編碼 print(json_ser,type(json_ser)) #注意引號,括號的變化,數據類型的變化。dest = json.loads(json_ser) print(dest) print(id(src),id(dest))#以上代碼執行結果如下: {"name": "Jason", "age": 20, "interest": ["music", "movie"], "class": ["python"]} <class 'str'> {'name': 'Jason', 'age': 20, 'interest': ['music', 'movie'], 'class': ['python']} 2114747181640 2114747436952三.MessagePack模塊
1.MessagePack概述
MessagePack是一個基于二進制高效的對象序列化類庫,可用于跨語言通信。
它可以像JSON那樣,在許多種語言之間交換結構對象。
但是它比JSON更快速也更輕巧。
支持Python,Ruby,Java,C/C++等眾多語言。宣稱比Google Protocol Buffers還要快4倍(這話建議大家聽聽就好,要以實際測試為準)。
兼容json和pickle。
2.MessagePack安裝
messagePack官網地址:https://msgpack.org/安裝messagePack方式:C:\Users\yinzhengjie>pip install msgpackCollecting msgpackDownloading https://files.pythonhosted.org/packages/41/0a/49b522c5b23006d60669ec8dc97558e91880673e170108e0e9e21fc452e3/msgpack-0.6.2-cp37-cp37m-win_amd64.whl (68kB)100% |████████████████████████████████| 71kB 112kB/sInstalling collected packages: msgpackSuccessfully installed msgpack-0.6.2C:\Users\yinzhengjie>3 . 常用方法
packb序列化對象。提供了dumps來兼容pickle和json。
unpackb反序列化對象。提供了loads來兼容。
pack序列化對象保存到文件對象。提供了dump來兼容。
unpack反序列化對象保存到文件對象。提供紅了load來兼容。
上面的內容了解一下即可,咱們生產環境中還是只用dump(s)和load(s)方法來進行序列化和反序列化,沒有必要記得太多,反而浪費腦細胞~嘿嘿嘿。
4.對比pickle,json和messagePack的序列化字節大小
''' 遇到問題沒人解答?小編創建了一個Python學習交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' #!/usr/bin/env python #_*_conding:utf-8_*_import pickle import json import msgpack#導入模塊,都是標識符 methods = (pickle,json,msgpack)src = {'person':[{'name':'Jason','age':18,'hobby':('movie','music','Mountain climbing')},{'name':'YinZhengjie','age':20,'hobby':('Basketball','ping-pong','Blogging')}],'total':2}#進行序列化操作 for method in methods:s1 = method.dumps(src)if method == json: #我們這里僅對json格式文件做一個簡單的壓縮處理,但生產環境建議不要這樣用,因為這樣寫邏輯并不嚴謹。s1 = s1.replace(' ','')print(method.__name__,type(s1),len(s1),s1)print("*" * 20 + "我是分割線" + "*" * 20)#進行反序列話操作 # s2 = msgpack.loads(s1,encoding="utf8") #這個方法不推薦使用,使用后會拋出"DeprecationWarning: encoding is deprecated, Use raw=False instead."的警告信息喲~ # print(type(s2),s2) s3 = msgpack.loads(s1,raw=False) #官方推薦使用"raw=False"的方式 print(type(s3),s3)#以上代碼執行結果如下: pickle <class 'bytes'> 225 b'\x80\x03}q\x00(X\x06\x00\x00\x00personq\x01]q\x02(}q\x03(X\x04\x00\x00\x00nameq\x04X\x05\x00\x00\x00Jasonq\x05X\x03\x00\x00\x00ageq\x06K\x12X\x05\x00\x00\x00hobbyq\x07X\x05\x00\x00\x00movieq\x08X\x05\x00\x00\x00musicq\tX\x11\x00\x00\x00Mountain climbingq\n\x87q\x0bu}q\x0c(h\x04X\x0b\x00\x00\x00YinZhengjieq\rh\x06K\x14h\x07X\n\x00\x00\x00Basketballq\x0eX\t\x00\x00\x00ping-pongq\x0fX\x08\x00\x00\x00Bloggingq\x10\x87q\x11ueX\x05\x00\x00\x00totalq\x12K\x02u.' json <class 'str'> 171 {"person":[{"name":"Jason","age":18,"hobby":["movie","music","Mountainclimbing"]},{"name":"YinZhengjie","age":20,"hobby":["Basketball","ping-pong","Blogging"]}],"total":2} msgpack <class 'bytes'> 130 b'\x82\xa6person\x92\x83\xa4name\xa5Jason\xa3age\x12\xa5hobby\x93\xa5movie\xa5music\xb1Mountain climbing\x83\xa4name\xabYinZhengjie\xa3age\x14\xa5hobby\x93\xaaBasketball\xa9ping-pong\xa8Blogging\xa5total\x02' ********************我是分割線******************** <class 'dict'> {'person': [{'name': 'Jason', 'age': 18, 'hobby': ['movie', 'music', 'Mountain climbing']}, {'name': 'YinZhengjie', 'age': 20, 'hobby': ['Basketball', 'ping-pong', 'Blogging']}], 'total': 2}5.總結
MessagePack簡單易用,高效壓縮,支持語言豐富。所以,用它序列化也是一種很好的選擇。Python很大大名鼎鼎的庫都是用了msgpack。
上例中,之所以pickle比json序列化的結果還要大,原因主要是pickle要解決所有python數據類型的序列化,要記錄各種數據類型包括自定義的類。而json只需要支持少數幾種類型,所以就可以很簡單,都不需要類型的描述字符。但大多數情況下,我們序列化的數據都是這些簡單的類型。
總結
以上是生活随笔為你收集整理的Python的序列化与反序列化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python组织文件 实践:查找大文件、
- 下一篇: Python语言防坑小技巧