Python開發之序列化與反序列化:pickle、json模塊使用詳解

1 引言

  在平常開發中,全部的對象都是存儲在內存當中,尤爲是像python這樣的堅持一切接對象的高級程序設計語言,一旦關機,在寫在內存中的數據都將不復存在。另外一方面,存儲在內存夠中的對象因爲編程語言、網絡環境等等因素,很難在網絡中進行傳輸交互。由此,就誕生了一種機制,能夠實現內存中的對象與方便持久化在磁盤中或在網絡中進行交互的數據格式(str、bites)之間的相互轉換。這種機制就叫序列化與發序列化:html

  序列化:將內存中的不可持久化和傳輸對象轉換爲可方便持久化和傳輸對象的過程。python

  反序列化:將可持久化和傳輸對象轉換爲不可持久化和傳輸對象的過程。web

  Python中提供pickle和json兩個模塊來實現序列化與反序列化,pickle模塊和json模塊dumps()、dump()、loads()、load()這是個函數,其中dumps()、dump()用於實現序列化,loads()、load()用於實現反序列化。下面,咱們分別對pickle和json模塊進行介紹。shell

2  pickle模塊

  pickle模塊的dumps()、dump()、loads()、load()是個函數按功能劃分能夠分爲兩組:
  序列化:dumps()、dump()
  反序列化:loads()、load()
   dumps()與dump()的區別是dumps()只是單純得將對象序列化,而dump()會在序列化以後將結果寫入到文件當中;與之對應,loads()與load()區別至於loads()是對dumps的序列化結果進行反序列化,而dump()會從文件中讀取內容進行反序列化。

2.1 dumps()與loads()

>>> import pickle >>> p_dict = {'name':'張三' , 'age':30 , 'isMarried':False} # 定義一個字典
>>> p_str = pickle.dumps(p_dict) # 序列化
>>> type(p_dict) <class 'dict'>
>>> type(p_str) <class 'bytes'>
>>> p_str b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x06\x00\x00\x00\xe5\xbc\xa0\xe4\xb8\x89q\x02X\x03\x00\x00\x00ageq\x03K\x1eX\t\x00\x00\x00isMarriedq\x04\x89u.'
>>> p = pickle.loads(p_str) >>> type(p) <class 'dict'>
>>> p {'name': '張三', 'age': 30, 'isMarried': False}
  能夠看到,反序列化後獲得的p和序列化以前的p_dict內容是如出一轍的。不過,p與p_dict已是兩個不一樣的對象了:
>>> id(p)==id(p_dict) False

2.2 dump()與load()

  序列化:
>>> import pickle >>> p_dict = {'name':'張三' , 'age':30 , 'isMarried':False} # 定義一個字典
>>> file = open("my_dump.txt", "wb") # 由於序列化只有的是bites類型,因此必須以wb模式打開
>>> pickle.dump(p_dict, file) >>> file.close()
  此時,經過上面代碼咱們已經將p_dict序列化成功,並寫入到了一個名爲my_dump.txt文件中。你能夠找到這個文件,而後將它拷貝到任何電腦上進行反序列化:
>>> file=open("my_dump.txt","rb") >>> p=pickle.load(file) >>> file.close() >>> type(p) <class 'dict'>
>>> p {'name': '張三', 'age': 30, 'isMarried': False}
  看,反序列化後獲得的內容與序列化以前的內容徹底同樣。體會到序列化與反序列化的做用了嗎?序列化以後的內容能夠方便得保存到磁盤中,電腦關機也不怕。

3 json模塊

  若是你閱讀並理解了上文中關於pickle的部門內容,對於這一部分的json模塊內容,你能夠不費吹灰之力掌握。上文中說到過,與pickle同樣,json模塊也提供了dumps()、dump()、loads()、load()則是個函數,且其中區別也與pickle中是個函數的區別是同樣的。

3.1 dumps()與loads()

>>> import pickle >>> p_dict = {'name':'張三' , 'age':30 , 'isMarried':False} # 定義一個字典
>>> import json >>> p_dict = {'name':'張三' , 'age':30 , 'isMarried':False} # 定義一個字典
>>> p_str = json.dumps(p_dict) >>> type(p_str) <class 'str'>
>>> p_str '{"name": "\\u5f20\\u4e09", "age": 30, "isMarried": false}'
  能夠看到,json序列化以後獲得的是json格式字符串,但上述json字符串中,中文部份內容顯示爲了「亂碼」。怎麼辦呢? json的dumps()函數(dump()函數也有)中提供了一個ensure_ascii參數,將該參數的值設置爲False,可令序列化後中文依然正常顯示。
>>> p_str2 = json.dumps(p_dict, ensure_ascii=False) >>> p_str2 '{"name": "張三", "age": 30, "isMarried": false}'
  接着上面的內容進行反序列化:
>>> p1 = json.loads(p_str) >>> p1 {'name': '張三', 'age': 30, 'isMarried': False} >>> p2 = json.loads(p_str) >>> p2 {'name': '張三', 'age': 30, 'isMarried': False}

3.2 dump()與load()

>>> import json >>> p_dict = {'name':'張三' , 'age':30 , 'isMarried':False} # 定義一個字典
>>> file = open('d:/mydump.txt' , 'w') >>> json.dump(p_dict , file) >>> file.close()
  固然,你也能夠加上ensure_ascii這一參數,並將其值設置爲False,這樣你打開mydump.txt文件裏面的中文就能正常顯示。(執行完代碼以後,本地會有一個mydump.txt文件,諸位能夠驗證該內容)
>>> file = open('d:/mydump.txt' , 'w') >>> json.dump(p_dict , file , ensure_ascii=False) >>> file.close()
  繼續反序列化:
>>> file = open('d:/mydump.txt' , 'r') >>> p = json.load(file) >>> file.close() >>> type(p) <class 'dict'>
>>> p {'name': '張三', 'age': 30, 'isMarried': False}
  經過上面內容,pickle和json模塊關於序列化與反序列化的操做就介紹完了。咱們能夠發現,pickle與json兩個模塊不管是在函數名,仍是在功能上,都是機器類似的。既然這樣,有了pickle模塊,爲何還有json模塊的誕生呢?接下來來講說pickle與json模塊的區別。

4 pickle模塊與json模塊的區別

   (1)pickle模塊用於Python語言特有的類型和用戶自定義類型與Python基本數據類型之間的轉換
  json模塊用於字符串和python數據類型間進行轉換。以下所示,咱們自定義一個Person類,分別用pickle和json進行序列化:
>>> class Person: def __init__(self , name , age , isMarried): self.name = name self.age = age self.isMarried = isMarried >>> p = Person('張三' , 30 , False)
  使用pickle模塊進行序列化與反序列化:
>>> p = Person('張三' , 30 , False) >>> import pickle >>> pp = pickle.dumps(p) >>> type(pp) <class 'bytes'>
>>> pp b'\x80\x03c__main__\nPerson\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x06\x00\x00\x00\xe5\xbc\xa0\xe4\xb8\x89q\x04X\x03\x00\x00\x00ageq\x05K\x1eX\t\x00\x00\x00isMarriedq\x06\x89ub.'
>>> p2 = pickle.loads(pp) >>> type(p2) <class '__main__.Person'>
>>> p2.name '張三'
  甚至pickle模塊還可以對Peron自己進行序列化:
>>> per = pickle.dumps(Person) >>> per b'\x80\x03c__main__\nPerson\nq\x00.'
>>> per2 = pickle.loads(per) >>> per2 <class '__main__.Person'>
  若是用json對Person實例對象進行序列化,就會報錯:
>>> import json >>> p = Person('張三' , 30 , False) >>> json.dumps(p) Traceback (most recent call last): File "<pyshell#49>", line 1, in <module> json.dumps(p) …… TypeError: Object of type 'Person' is not JSON serializable
   若是非要用json對Person對象進行序列化,必須先定義一個將Person對象轉化爲字典(dict)的方法
>>> def person2dict(per): return { 'name':per.name , 'age':per.age , 'isMarried':per.isMarried } >>> p3 = json.dumps(p , default=person2dict) >>> type(p3) <class 'str'>
>>> p3 '{"name": "\\u5f20\\u4e09", "age": 30, "isMarried": false}'
>>> p3 = json.dumps(p , default=person2dict , ensure_ascii=False) >>> type(p3) <class 'str'>
>>> p3 '{"name": "張三", "age": 30, "isMarried": false}'
  固然,也不能直接進行反序列化,否則也只會獲得一個字典:
>>> p4 = json.loads(p3) >>> type(p4) <class 'dict'>
>>> p4 {'name': '張三', 'age': 30, 'isMarried': False}
  此時,也要定義一個將字典轉換爲Person類實例的方法,在進行反序列化:
>>> def dict2person(d): return Person(d['name'],d['age'],d['isMarried']) >>> p5 = json.loads(p3 , object_hook=dict2person) >>> type(p5) <class '__main__.Person'>
>>> p5.name '張三'
  (2)pickle序列化結果爲bites類型,只適合於Python機器之間的交互。
    json序列化結果爲str類型,可以被多種語言識別,可用於與其餘程序設計語言交互。
  目前,JSON格式字符串已經成爲網絡傳輸中的一種標準格式,因此在web後臺開發中一般用json模塊來序列化而不是pickle模塊。
   JSON和Python內置的數據類型對應以下:
JSON類型
Python類型
{}
dict
[]
list
"string"
'str'或u'unicode'
1234.56
int或float
true/false
True/False
null
None

5 總結

  (1)序列化與反序列化是爲了解決內存中對象的持久化與傳輸問題;
  (2)Python中提供了pickle和json兩個模塊進行序列化與反序列化;
  (3)dumps()和dump()用於序列化,loads()和load()用於反序列化;
  (4)pickle模塊能序列化任何對象,序列化結果爲bites類型,只適合於Python機器之間交互;
  json模塊只能序列化Python基本類型,序列化結果爲json格式字符串,適合不一樣開發語言之間交互。

原文出處:https://www.cnblogs.com/chenhuabin/p/10502096.html編程

相關文章
相關標籤/搜索