python3之序列化(pickle&json&shelve)


1、pickle模塊

python持久化的存儲數據:

python程序運行中得到了一些字符串,列表,字典等數據,想要長久的保存下來,方便以后使用,而不是簡單的放入內存中關機斷電就丟失數據。python模塊大全中pickle模塊就排上用場了, 他可以將對象轉換為一種可以傳輸或存儲的格式。

pickle模塊將任意一個python對象轉換成一系統字節的這個操作過程叫做串行化對象。

python的pickle模塊實現了python的所有數據序列和反序列化。基本上功能使用和JSON模塊沒有太大區別,方法也同樣是dumps/dump和loads/load。cPickle是pickle模塊的C語言編譯版本相對速度更快。

與JSON不同的是pickle不是用於多種語言間的數據傳輸,它僅作為python對象的持久化或者python程序間進行互相傳輸對象的方法,因此它支持了python所有的數據類型。

import pickle

data2 = [1,2,3,4]
det_str = pickle.dumps(data2)
print(det_str)

#output:  輸出為二進制格式 
b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04e.'


#將數據序列化后存儲到文件中
f = open('test.txt','wb')   #pickle只能以二進制格式存儲數據到文件
data = {'k1':'python','k2':'java'}
f.write(pickle.dumps(data))   #dumps序列化源數據后寫入文件
f.close()

#反序列化讀取源數據
import pickle
f = open('test.txt','rb')
da = pickle.loads(f.read())   #使用loads反序列化
print(da)

dumps和dump,load和loads的區別:

dumps是將對象序列化

dump是將對象序列化並保存到文件中

loads將序列化字符串反序列化

load將序列化字符串從文件讀取並反序列化

import pickle

data1 = [1,'a',2,'b',3,'c']
pi = pickle.dumps(data1)  #序列化對象
print(pi)
print(pickle.loads(pi))    #反序列化對象


f = open('test1.txt','wb')
data2 = ['py','th','on',123]
pickle.dump(data2,f)    #序列化對象到文件
f = open('test1.txt','rb')
red = pickle.load(f)   #從文件中反序列化對象
print(red)

2、json模塊

JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。它基於ECMAScript的一個子集。 JSON采用完全獨立於語言的文本格式,但是也使用了類似於C語言家族的習慣(包括C、C++、Java、JavaScript、Perl、Python等)。這些特性使JSON成為理想的數據交換語言。易於人閱讀和編寫,同時也易於機器解析和生成(一般用於提升網絡傳輸速率)。

json.dump(obj,fp,*,skipkeys = False,ensure_ascii = True,check_circular = True,indent = None,separators = None,default = None,sort_keys = False,** kw)

將obj對象格式化並存儲到文件對象中,文件必須為可寫的文件句柄,json只產生str對象,不支持bytes對象,所以fp.write()必須支持str輸入

skipkeys如果為True,對象的基本類型必須是str,int,float,bool,None

ensure_ascii=True,如果為true則所以傳入的非ASCII字符都被轉義,如果為false則字符將原樣輸出

check_circular=True,如果為true容器類型的循環引用檢查將被跳過

indent=None,表示數組元素和對象將按指定的值縮進,可以是整數或字符串如'\t'

sort_keys=False,如果為True字典的輸出將按鍵排序

import json

data=[{'k1':'v1','k2':'v2'},{'k3':'v3','k4':'k4'},{'k6':'v6','k5':'k5'}]

with open('test.txt','w') as pf:
    json.dump(data,pf,indent=2,sort_keys=True)
    pf.close()

#output
[
  {
    "k1": "v1",
    "k2": "v2"
  },
  {
    "k3": "v3",
    "k4": "k4"
  },
  {
    "k5": "k5",
    "k6": "v6"
  }
]

json.dumps(obj,*,skipkeys = False,ensure_ascii = True,check_circular = True,indent = None,separators = None,default = None,sort_keys = False,** kw)

將obj對象格式化為str對象,參數含義和dump相同

import json
data=[{'k1':'v1','k2':'v2'},{'k3':'v3','k4':'k4'},{'k6':'v6','k5':'k5'}]

pi = json.dumps(data,indent=2,sort_keys=True)
print(type(pi))
print(pi)
p2=json.loads(pi)
print(type(p2))
print(p2)

#
<class 'str'>
[
  {
    "k1": "v1",
    "k2": "v2"
  },
  {
    "k3": "v3",
    "k4": "k4"
  },
  {
    "k5": "k5",
    "k6": "v6"
  }
]
<class 'list'>
[{'k1': 'v1', 'k2': 'v2'}, {'k3': 'v3', 'k4': 'k4'}, {'k5': 'k5', 'k6': 'v6'}]

json.load(fp,*,cls=None,object_hook=None,parse_float=None,parse_int=None,parse_constant=None,object_pairs_hook=None,**kw)

將文件對象反序列化為python對象,選項參數用來指定類型解碼,在python3.6中fp可以使用二進制文件

import json

with open('test.txt','rb') as fp:
    data1=json.load(fp)
    print(type(data1))
    print(data1)

#
<class 'list'>
[{'k1': 'v1', 'k2': 'v2'}, {'k3': 'v3', 'k4': 'k4'}, {'k5': 'k5', 'k6': 'v6'}]

json.loads(s,*,encoding=None,cls=None,object_hook=None,parse_float=None,parse_int=None,parse_constant=None,object_pairs_hook=None,**kw)

將json文檔的實例反序列化為python對象,參數含義同load()相同

import json
with open('test.txt','rb') as fp:
    data1=json.loads(fp.read())
    print(type(data1))
    print(data1)

3、json與pickle模塊的區別

1、JSON只能處理基本數據類型。pickle能處理所有Python的數據類型。

2、JSON用於各種語言之間的字符轉換。pickle用於Python程序對象的持久化或者Python程序間對象網絡傳輸,但不同版本的Python序列化可能還有差異。

 4、shelve模塊

shelve與pickle類似用來持久化數據的,不過shelve是以鍵值對的形式,將內存中的數據通過文件持久化,值支持任何pickle支持的python數據格式,它會在目錄下生成三個文件。

>>> import shelve
>>> import tab
>>> s = shelve.open('test_s.db')   #創建shelve並打開
>>> s['k1']={'int':10,'float':8.8,'string':'python'}  #寫入數據
>>> s.close()    #關閉文件
>>> s = shelve.open('test_s.db')   #打開文件
>>> print(s['k1'])    #訪問shelve中的數據
{'float': 8.8, 'string': 'python', 'int': 10}
>>> print(s['k1']['int'])
10
>>> s.close()

對於存儲的key,value值,只能添加key,value,可修改整個value,不能單獨修改列表或字典中的元素

>>> s = shelve.open('test_s.db',flag='r')
>>> print(s['k1'])
{'float': 8.8, 'string': 'python', 'int': 10}
>>> s['k2']=[1,2,3]    #添加數據
>>> print(s['k2'])
[1, 2, 3]
>>> s['k2'][0]=99   #修改存儲的value的單個值時不生效也不報錯
>>> print(s['k2'])
[1, 2, 3]
>>> s.close()

>>> s = shelve.open('test_s.db',flag='c')
>>> s.keys()
KeysView(<shelve.DbfilenameShelf object at 0x7fd4770f1850>)
>>> len(s)
2
>>> s['k2']=(33,44)   #可以修改key的value
>>> print(s)
<shelve.DbfilenameShelf object at 0x7fd4770f1850>
>>> print(s['k2'])
(33, 44)

寫回(write-back)由於shelve在默認情況下是不會記錄待持久化對象的任何修改的,所以我們在shelve.open()時候需要修改默認參數,否則對象的修改不會保存。

上面這個例子中,由於一開始我們使用了缺省參數shelve.open()了,因此修改的值即使我們s.close()也不會被保存。

所以當我們試圖讓shelve去自動捕獲對象的變化,我們應該在打開shelf的時候將writeback設置為True。當我們將writeback這個flag設置為True以后,shelf將會將所有從DB中讀取的對象存放到一個內存緩存。當我們close()打開的shelf的時候,緩存中所有的對象會被重新寫入DB。

>>> s = shelve.open('test_s.db',writeback=True)  #使用回寫功能打開
>>> print(s['k1'])   #初始值
{'float': 8.8, 'string': 'python', 'int': 10}
>>> print(s['k2'])
(33, 44)
>>> s['k1']['float']='99.99'  #修改字典中的元素
>>> print(s['k1'])   #成功修改
{'float': '99.99', 'string': 'python', 'int': 10}

writeback方式有優點也有缺點。優點是減少了我們出錯的概率,並且讓對象的持久化對用戶更加的透明了;但這種方式並不是所有的情況下都需要,首先,使用writeback以后,shelf在open()的時候會增加額外的內存消耗,並且當DB在close()的時候會將緩存中的每一個對象都寫入到DB,這也會帶來額外的等待時間。因為shelve沒有辦法知道緩存中哪些對象修改了,哪些對象沒有修改,因此所有的對象都會被寫入。

>>> print(s['k1'])
{'float': '99.99', 'string': 'python', 'int': 10}
>>> s['k1']['list']=[1,2,3]
>>> s['k1']['tuple']=(4,5,6)
>>> s['k1']['dic']={'a':123,'b':456}
>>> print(s['k1'])
{'dic': {'b': 456, 'a': 123}, 'int': 10, 'float': '99.99', 'string': 'python', 'tuple': (4, 5, 6), 'list': [1, 2, 3]}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM