天天看點

Python 基礎之序列化子產品

序列化

概念

将原本的字典、清單等内容轉換成一個字元串的過程就叫做序列化。如:将 Python 代碼轉為文本,友善移植,轉化文本這個過程為序列化。

目的

  1. 以某種存儲形式使自定義對象持久化;
  2. 轉移對象,友善攜帶移植;
  3. 使程式更具有維護性。
Python 基礎之序列化子產品

json

使用 json 函數要先導入 json 函數庫:import json

dump和dumps  序列化方法。

  • dump:必須傳檔案描述符,将序列化的檔案儲存在檔案中。
  • dumps:把資料結構直接轉化為 json 字元串形式(較為常用)。

将下列資料編碼轉化為json格式:

import json

data = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
json = json.dumps(data)
print(json, type(json))
           

結果:

{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5} <class 'str'>

Process finished with exit code 0

可以看到輸出的 json 為字元串對象,下面我們來對比一下 Python 中的資料結構轉化 json 的形式為:

Python json
dict object
list, tuple array
str, unicode string
int, long, float number
True true
False false
None null

load和loads  反序列化方法

  • load:用于接收檔案描述符,完成讀取檔案和反序列化。
  • loads:把 json 字元串形式直接轉化為資料結構(反序列化,較為常用)。
import json

json_data = '{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}'
content = json.loads(json_data)
print(content, type(content))
           

結果:

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} <class 'dict'>

Process finished with exit code 0

注意:字典引号,json 對象中字典的是雙引号,否則報錯。

反過來,我們來看看 json 類型轉化為 Python 類型的對照表:

json Python
object dict
array list
string unicode
number (int) int, long
number (real) float
true True
false False
null None

json與demjson

demjson 是 python 的第三方子產品庫,可用于編碼和解碼 json 資料,包含了 jsonLint 的格式化及校驗功能。

Github 位址:https://github.com/dmeranda/demjson

官方位址:http://deron.meranda.us/python/demjson/

安裝介紹:http://deron.meranda.us/python/demjson/install

encode和decode函數

  • encode:将 Python 對象編碼成 json 字元串。
  • decode:将已編碼的 json 字元串解碼為 Python 對象

(實作代碼如json,在這裡不做示範。)

pickle

與 json 都是序列化子產品,差別如下:

  • json:用于字元串 和 python 資料類型間進行轉換。
  • pickle:用于 python 特有的類型 和 python 的資料類型間進行轉換,pickle類型的資料為二進制。

pickle 中的方法和 json 相同,都有 load、loads、dump 和 dumps。下面示範 dumps 和 loads 用法:

import pickle

dict_data_one = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
pickle_data = pickle.dumps(dict_data_one)  # serialization
print(pickle_data)  # binary

dict_data_two = pickle.loads(pickle_data)  # deserialization
print(dict_data_two)
           

結果:

b'\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01K\x01X\x01\x00\x00\x00bq\x02K\x02X\x01\x00\x00\x00cq\x03K\x03X\x01\x00\x00\x00dq\x04K\x04X\x01\x00\x00\x00eq\x05K\x05u.'

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Process finished with exit code 0

下面展示 dump 和 load 用法:

import time
import pickle

structure_time_one = time.localtime()
print(structure_time_one)
f = open('pickle_file', 'wb')
pickle.dump(structure_time_one, f)
f.close()

f = open('pickle_file', 'rb')
structure_time_two = pickle.load(f)
print(structure_time_two.tm_year,
      structure_time_two.tm_mon,
      structure_time_two.tm_mday)
           

結果:

time.struct_time(tm_year=2018, tm_mon=8, tm_mday=13, tm_hour=21, tm_min=41, tm_sec=50, tm_wday=0, tm_yday=225, tm_isdst=0)

2018 8 13

Process finished with exit code 0

shelve

shelve 也是 python 提供給我們的序列化工具,比 pickle 用起來更簡單一些。shelve 隻提供給我們一個 open 方法,是用 key 來通路的,使用起來和字典類似。

import shelve

f = shelve.open('shelve_file')
'''operate on the file handle and store the data'''
f['key'] = {'int': 10, 'float': 9.5, 'string': 'Sample data'}
f.close()

f = shelve.open('shelve_file')
content = f['key']
f.close()

print(content)
           

結果:

{'int': 10, 'float': 9.5, 'string': 'Sample data'}

Process finished with exit code 0

這個子產品有個限制,它不支援多個應用同一時間往同一個 DB 進行寫操作。是以當我們知道我們的應用如果隻進行讀操作,我們可以讓shelve 通過隻讀方式打開 DB。

由于 shelve 在預設情況下是不會記錄待持久化對象的任何修改的,是以我們在 shelve.open() 時候需要修改預設參數,否則對象的修改不會儲存。

import shelve

f1 = shelve.open('shelve_file')
print(f1['key'])
f1['key']['new_value'] = 'this was not here before'
f1.close()

f2 = shelve.open('shelve_file', writeback=True)
print(f2['key'])
f2['key']['new_value'] = 'this was not here before'
f2.close()
           

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