day5-python中的序列化與反序列化-json&pickle

1、概述

玩過稍微大型一點的遊戲的朋友都知道,不少遊戲的存檔功能使得咱們能夠方便地迅速進入上一次退出的狀態(包括裝備、等級、經驗值等在內的一切運行時數據),那麼在程序開發中也存在這樣的需求:比較簡單的程序,對象的處理都在內存中直接實現,程序退出後對象就消失;但對於功能需求稍微拔高一點的程序來說,不少時候每每須要須要把對象持久化保存起來,以便下次啓動程序時還能直接進入最後一次的狀態。html

這個處理過程在程序開發中就是序列化與反序列化。python

2、序列化與反序列化的概念

概述中引入了一個遊戲存檔的場景,本質上是遊戲程序把運行時的對象轉換成能夠持久存儲的對象,而後保存(到數據庫)的過程。仍是以這個爲引子來說講序列化與反序列化的概念(如下概念整合自網絡資料,我的認爲解釋比較到位了)。數據庫

  • 序列化
    咱們把程序運行時內存中的數據結構或對象轉換成二進制串字節序列的過程稱之爲序列化,這樣咱們就能夠對對象實現持久化存儲或網絡傳輸。
    請注意如下重點:
    1. 序列化的對象
       
    內存中的數據結構或對象,也就是咱們在程序運行中操縱的一切對象(這是一個面向對象的時代,固然包括不少地方說的變量啦~)
    2. 序列化後的對象
       
    變爲二進制串字節序列,這個不做過多解釋,要持久化保存到硬件或進行網絡傳輸,必須是bytes對象。
    3. 序列化的目的
       
    想一想本身玩遊戲時存檔的那種便利性和必要性把,有些對象必須可以持久化地保存(通常文件,數據庫,巴拉巴拉…)或進行網絡傳輸(分佈式程序),才能知足功能需求。
  • 反序列化
    反序列化就是序列化的逆向過程,持久化保存或網絡傳輸數據的最終目的也是爲了後續使用,必須能夠逆向加載到內存中二次利用,這就是反序列化。

python中的序列化與反序列化模塊有json和pickle,下面就來看看怎麼玩轉它們。編程

3、json模塊

json模塊提供了dumps,loads,dump和load四種方法,下面展開來闡述:json

  1. dumps序列化和loads反序列化
    dumps和loads是成對出現的:
    dumps用於將python中的簡單數據類型(典型的是字典和列表,還有字符串)進行json格式encode編碼,轉換爲符合json格式的字符串(返回標準的json格式字符串);
    loads則恰好相反,用於把符合json格式的字符串decode成python中特定的數據類型(注意是簡單的數據類型,下文會詳細解釋)。
     1 >>> import json
     2 >>> list1=['a','b','c']
     3 >>> print(type(list))
     4 <class 'type'>
     5 
     6 #dumps序列化,能夠理解爲encode json過程
     7 >>> print(json.dumps(list1))
     8 ["a", "b", "c"]
     9 >>> print(type(json.dumps(list1)))
     10 <class 'str'>   #list dumps處理後變爲str類型
     11 >>> dict1={'id':'001','name':'Maxwell'}
     12 >>> print(type(dict1))
     13 <class 'dict'>
     14 >>> print(type(json.dumps(dict1)))
     15 <class 'str'>   #dict通過dumps處理後也變成str類型
     16 >>>
     17 
     18 #loads反序列化
     19 >>> print(json.loads(json.dumps(list1)))
     20 ['a', 'b', 'c']
     21 >>> print(json.loads(json.dumps(dict1)))
     22 {'id': '001', 'name': 'Maxwell'}
     23 >>> print(type(json.loads(json.dumps(list1))))
     24 <class 'list'>  #把通過json dumps處理過的字符串loads序列化,可還原爲原來的數據類型
     25 >>> print(type(json.loads(json.dumps(dict1))))
     26 <class 'dict'>  #把通過json dumps處理過的字符串loads序列化,可還原爲原來的數據類型
    以上代碼僅僅是展現loads方法的效果,實際使用中咱們能夠把符合python中json格式的自定義字符串(好比程序中的輸入)轉換成特定的數據類型,這樣就能夠在程序中跑起來:
     1 >>> str1='["a", "b", "c"]'
     2 >>> print(type(json.loads(str1)))
     3 <class 'list'>  #反序列化爲list
     4 >>> print(json.loads(str1))
     5 ['a', 'b', 'c']
     6 >>> str2='{"id":"001","name":"Maxwell"}'
     7 >>> print(json.loads(str2))
     8 {'id': '001', 'name': 'Maxwell'}
     9 >>> print(json.loads(str2))
     10 {'id': '001', 'name': 'Maxwell'}
     11 >>> print(type(json.loads(str2)))
     12 <class 'dict'>  #反序列化爲dict
    注意:經過loads方法反序列化自定義的字符串時,外層的引號必須是單引號,內層的引號是雙引號(能夠對照dumps後輸出的引號是雙引號來看),這是python的規範,別問爲何了。

    好了,以上展現了dumps和loads的處理過程,咱們的目的不是把python中的運行時對象能進行持久化保存或網絡傳輸嗎?下面展現經過dumps處理後保存到文本文件和從文本文件中loads出歷史保存的數據效果:
    (1) dumps序列化後保存
     1 import json
     2 dict1={'id':'001','name':'Maxwell'}
     3 with open('dumps.txt','w',encoding='utf-8') as f:
     4     f.write(json.dumps(dict1))
     5
    看看保存後的文本文件dumps.txt的內容:
    image

    (2) loads反序列化從文件中加載數據
     1 >>> import json
     2 >>> with open('dumps.txt','r',encoding='utf-8') as f:
     3 ...     content = f.read()
     4 >>> print(json.loads(content))
     5 {'id': '001', 'name': 'Maxwell'}
     6 >>> print(type(json.loads(content)))
     7 <class 'dict'>  #loads反序列化後成功還原爲原來的數據類型dict
     8 >>> print(json.loads(content).get('name'))
     9 Maxwell  #此時能夠應用dict的各類大法了
     10 >>> print(json.loads(content)['name'])
     11 Maxwell
  2. dump序列化和load反序列化
    dump和load也是成對出現的,dump能夠把python中的特定數據類型(比較多用的仍是dict和list)轉換爲json格式,並直接寫入寫入一個file-like Object(操做的對象包括未轉換的python對象和file-like Object),load則與此相反,可從文件對象中反序列化出python的原生對象出來。
     1 >>> import json
     2 >>> dict1={'id': '001', 'name': 'Maxwell'}
     3 >>> with open('dump.txt','w',encoding='utf-8') as f:
     4 ...     json.dump(dict1,f)   #dump序列化,直接操做原生數據類型對象和文件句柄
     5 ...
     6 
     7 #load反序列化
     8 >>> with open('dump.txt','r',encoding='utf-8') as f:
     9 ...     content = json.load(f)  #注意這裏先用一個對象把load的內容保存起來,不然關閉文件後就不能再訪問了
     10 ...
     11 >>> print(content)
     12 {'id': '001', 'name': 'Maxwell'}
     13 >>> print(type(content))
     14 <class 'dict'>   #成功反序列化成dict
     15 >>> print(content['name'])
     16 Maxwell          #試試dict大法
  3. (dumps & loads) VS (dump & load)
    對比下dumps & loads和dump & load吧:
    (1)dumps & loads
           只能解決python中能夠被json模塊處理的對象和json格式字符串之間相互轉換的問題,它們操做的對象分別是能夠被json模塊處理的對象和json格式  
           字符串。
    (2)dump和load
            能夠理解爲json文件處理函數,操做的對象是python中能夠被json模塊處理的對象和file-like Object,屏蔽或者說省略了json格式字符串這一細節
    綜合對比起來,若是要經過文件保存或從文件中加載運行時對象,使用dump和load更方便,代碼更少;反之若是僅僅須要進行json格式處理,則建議使用dumps和loads。

4、pickle

pickle模塊實現了用於對Python對象結構進行序列化和反序列化的二進制協議,與json模塊不一樣的是pickle模塊序列化和反序列化的過程分別叫作 pickling 和 unpickling,且轉換先後是二進制字節碼,再也不是簡單的可閱讀的字符串:網絡

  • pickling: 是將Python對象轉換爲字節流的過程;
  • unpickling: 是將字節流二進制文件或字節對象轉換回Python對象的過程;
  1. dumps序列化和loads反序列化
    與jsonddumps和loads很是相似,不一樣的就在於轉換後的格式是二進制字節碼
     1 >>> import pickle
     2 >>> dict1={'id':'001','name':'Maxwell'}
     3 >>> pickle.dumps(dict1)
     4 b'\x80\x03}q\x00(X\x02\x00\x00\x00idq\x01X\x03\x00\x00\x00001q\x02X\x04\x00\x00\
     5 x00nameq\x03X\x07\x00\x00\x00Maxwellq\x04u.' #序列化成二進制字節碼
     6 >>> print(type(pickle.dumps(dict1)))
     7 <class 'bytes'>
     8 >>> pickle.loads(pickle.dumps(dict1))        #成功反序列化
     9 {'id': '001', 'name': 'Maxwell'}
     10 >>> print(type(pickle.loads(pickle.dumps(dict1))))
     11 <class 'dict'>
     12 >>> pickle.loads(pickle.dumps(dict1))['name']
     13 'Maxwell'
    因爲pickle序列化後數據類型變爲二進制字節碼,所以在保存文件和讀取文件時須要分別以wb和rb模式打開:
     1 >>> import pickle
     2 >>> dict1={'id':'001','name':'Maxwell'}
     3 >>> with open('picklt.txt','wb') as f:  #以wb模式打開文件後寫入dumps內容
     4 ...     f.write(pickle.dumps(dict1))
     5 ...
     6 
     7 >>> with open('picklt.txt','rb') as f:  #以rb模式打開後讀取內容
     8 ...     data = pickle.loads(f.read())
     9 ...
     10 >>> print(data)
     11 {'id': '001', 'name': 'Maxwell'}
    經過dumps寫入後,因爲是二進制字節碼,因此打開會有亂碼顯示了:
    image
  2. dump序列化和load反序列化
    同理,pickle的dump序列化和load反序列化也和json的dump、load很是相似,仍是看相同的例子吧:
     1 >>> import pickle
     2 >>> dict1={'id': '001', 'name': 'Maxwell'}
     3 >>> with open('pickle.txt','wb') as f:
     4 ...     pickle.dump(dict1,f)
     5 ...
     6 >>> with open('pickle.txt','rb') as f:
     7 ...     content = pickle.load(f)
     8 ...
     9 >>> print(content)
     10 {'id': '001', 'name': 'Maxwell'}
     11 >>> print(content['name'])
     12 Maxwell
    dump保存寫入的文件內容:
    image
  3. 序列化函數
    (1)序列化
     1 # !/usr/bin/env python
     2 # -*- coding: utf-8 -*-
     3 __author__ = 'Maxwell'
     4 
     5 import pickle
     6 
     7 def sayhi(name):
     8     print('Hello:', name)
     9 
     10 info = {'name':'Maxwell', 'func':sayhi}  #func對應的值是一個函數
     11 
     12 with open('test.txt', 'wb') as f:
     13     data = pickle.dumps(info)
     14     f.write(data)
     15

    (2)反序列化
     1 # !/usr/bin/env python
     2 # -*- coding: utf-8 -*-
     3 __author__ = 'Maxwell'
     4 
     5 import pickle
     6 
     7 def sayhi(name):   #此處須要定義出函數,由於它不能被直接加載到內存中
     8     print('Hello:',name)
     9 
     10 with open('test.txt','rb') as f:
     11     data = pickle.loads(f.read())
     12 
     13 print(data.get('name'))
     14 data.get('func')('Tom')
     15 
     16 結果輸出:
     17 Maxwell
     18 Hello: Tom

4、json和pickle對比

  • JSON是一種文本序列化格式(它輸出的是unicode文件,大多數時候會被編碼爲utf-8),而pickle是一個二進制序列化格式;
  • JOSN處理的是python對象和字符串的轉換問題,是咱們能夠讀懂的數據格式,而pickle是二進制格式,咱們沒法讀懂;
  • JSON是與特定的編程語言或系統無關的,且它在Python生態系統以外被普遍使用,而pickle使用的數據格式是特定於Python的;
  • 默認狀況下,JSON只能表示Python內建數據類型,並且是僅限於比較簡單的數據類型,如dict,list和str,對於自定義數據類型須要一些額外的工做來完成;pickle能夠直接表示大量的Python數據類型,包括自定數據類型(其中,許可能是經過巧妙地使用Python內省功能自動實現的;複雜的狀況能夠經過實現specific object API來解決)

以上內容摘自http://www.cnblogs.com/yyds/p/6563608.html
數據結構

相關文章
相關標籤/搜索