什么是序列化,把程序中的對象或者變量,從內(nèi)存中轉(zhuǎn)換為可存儲或可傳輸?shù)倪^程稱為序列化。在 Python 中,這個(gè)過程稱為 pickling,在其他語言中也被稱為 serialization,marshalling,flattening 等。程序中的對象(或者變量)在序列化之后,就可以直接存放到存儲設(shè)備上,或者直接發(fā)送到網(wǎng)絡(luò)上進(jìn)行傳輸。
從網(wǎng)站建設(shè)到定制行業(yè)解決方案,為提供網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站服務(wù)體系,各種行業(yè)企業(yè)客戶提供網(wǎng)站建設(shè)解決方案,助力業(yè)務(wù)快速發(fā)展。創(chuàng)新互聯(lián)將不斷加快創(chuàng)新步伐,提供優(yōu)質(zhì)的建站服務(wù)。序列化的逆向過程,即為反序列化(unpickling),就是把序列化的對象(或者變量)重新讀到內(nèi)存中~
json 模塊就用于序列化和反序列化。對象(變量)使用json模塊序列化后,表現(xiàn)為一個(gè)字符串,序列化為字符串格式的好處是:序列化后的對象可以在不同的編程語言之間傳遞。
?
python 數(shù)據(jù)類型和 json 中的字符串對應(yīng)關(guān)系如下:
python數(shù)據(jù)類型 | json字符串 |
---|---|
dict | '{}' |
list | '[]' |
tuple | '[]' |
str | 'string' |
int/float | '1.23' |
True/False | true/false |
None | null |
json模塊常用的就4個(gè)方法:dump,dumps,load,loads~
這兩個(gè)方法用于序列化對象,兩個(gè)方法的功能類似,區(qū)別在于,json.dumps 方法接收一個(gè)參數(shù),即需要序列化的對象,其余參數(shù)為可選參數(shù),方法執(zhí)行完成后,會返回序列化后得到的字符串;json.dump 接收兩個(gè)參數(shù),第一個(gè)參數(shù)和 dumps方法 相同,即需要序列化的對象,第二個(gè)參數(shù)為文件對象,例如 open方法 的返回對象,其余為可選參數(shù),方法執(zhí)行后,序列化后的字符串會直接寫到文件中~
?
dump / dumps 示例:
import json
d = {'name': '貝貝', 'age': 18}
lst = [1, 2, 3]
tup = ('a', 'b', 'c')
s = 'hello'
i = 3
f = 1.2
flag_1 = True
flag_2 = False
abc = None
print(type(json.dumps(d))) # <class 'str'>
print(json.dumps(d)) # {"name": "\u8d1d\u8d1d", "age": 18}
print(json.dumps(lst)) # [1, 2, 3]
print(json.dumps(tup)) # ["a", "b", "c"]
print(json.dumps(s)) # "hello"
print(json.dumps(i)) # 3
print(json.dumps(f)) # 1.2
print(json.dumps(flag_1)) # true
print(json.dumps(flag_2)) # false
print(json.dumps(abc)) # null
# 以上的輸出類型都是 class 'str' 類型,即字符串類型~
#################################
d = {'name': '貝貝', 'age': 18}
with open(file='/tmp/test_json', mode='w') as f:
json.dump(d, f)
# 執(zhí)行完成后,查看輸出的文件內(nèi)容:
? ~ cat /tmp/test_json
{"name": "\u8d1d\u8d1d", "age": 18}%
這兩個(gè)方法用于序列化后的字符串 反序列化,兩者的區(qū)別和 dump、dumps 類似,json.loads 接收一個(gè)字符串參數(shù),其余參數(shù)為可選參數(shù),json.load 也接收一個(gè)參數(shù),該參數(shù)為包含 json 字符串的文件對象~
json.loads示例:
d = json.loads('{"name": "\u8d1d\u8d1d", "age": 18}')
print(type(d), '--', d)
abc = json.loads('null')
print(type(abc), '--', abc)
tup = json.loads('["a", "b", "c"]')
print(type(tup), '--', tup)
s = json.loads('"hello"')
print(type(s), '--', s)
# 輸出結(jié)果:
<class 'dict'> -- {'name': '貝貝', 'age': 18}
<class 'NoneType'> -- None
<class 'list'> -- ['a', 'b', 'c']
<class 'str'> -- hello
注意:傳遞給 json.loads 方法的參數(shù)必須用 單引號括起來,里面的字符串使用雙引號,例如不能有這樣的寫法:json.loads("hello"),json.loads("['a', 'b', 'c']"),json 字符串中不支持單引號~
?
json.load示例:
with open(file='/tmp/test_json', mode='r') as f:
json_data = json.load(f)
print(type(json_data), '--', json_data)
# 輸出結(jié)果:
<class 'dict'> -- {'name': '貝貝', 'age': 18}
我們可以看到上述示例中,字典對象中包含有中文字符,在進(jìn)行序列化后,不管是使用 dumps 存放到字符串中 還是使用 dump 存放到文件中,中文字符串是使用 unicode 編碼格式存放的。
?
在Python3中,代碼中的字符串都是使用 unicode 格式存放的,序列化之后也是以unicode 格式存放,所以序列化和反序列化過程都不存在問題。
Python2中,代碼中的字符串是 str類型,str類型 和 unicode類型 的關(guān)系如下所示:
unicode -----> encode --------> str(例如為 utf-8編碼)
utf-8(例如為 utf-8編碼) --------> decode ----------> unicode
所以在Python2中,序列化過程和反序列化過程都有涉及到轉(zhuǎn)碼過程(encode和decode),序列化過程 會先將對象中的字符串 使用utf-8 進(jìn)行解碼(decode),轉(zhuǎn)換為unicode類型后,再存放到文件或者字符串中,反序列化過程 會將 json字符串 使用utf-8 編碼(encode),然后存放到內(nèi)存中的變量~
?
說明:在Python2中,dumps(dump)和loads(load)默認(rèn)使用 utf-8 進(jìn)行 encode和decode,若要使用使用其他編碼方式,可以通過 encode參數(shù) 指定;在Python3中,dumps(dump)和loads(load)方法都沒有 encode參數(shù)~
?
來看如下示例:
# -*- coding:utf-8 -*-
d = {'name': '貝貝', 'age': 18}
print type(json.dumps(d)), '--', json.dumps(d)
res_d = json.loads('{"age": 18, "name": "\u8d1d\u8d1d"}')
print type(res_d), '--', res_d
# 結(jié)果輸出:
<type 'str'> -- {"age": 18, "name": "\u8d1d\u8d1d"}
<type 'dict'> -- {u'age': 18, u'name': u'\u8d1d\u8d1d'}
如上過程,序列化和反序列化都沒有問題,這是因?yàn)?,文件的開頭指定了 ‘# -- coding:utf-8 --’,程序中的字符串(str類型)就是使用utf-8編碼后存放于內(nèi)存中~
?
現(xiàn)在修改一下文件開頭的編碼:
# -*- coding:gbk -*-
d = {'name': '貝貝', 'age': 18}
print type(json.dumps(d)), '--', json.dumps(d)
res_d = json.loads('{"age": 18, "name": "\u8d1d\u8d1d"}')
print type(res_d), '--', res_d
這個(gè)時(shí)候就會報(bào)出如下錯(cuò)誤信息,很簡單,utf-8 無法解碼 gbk編碼的字符串('貝貝')
UnicodeDecodeError: 'utf8' codec can't decode byte 0xb1 in position 0: invalid start byte
解決方法就是,在 dumps 過程中指定使用 gbk 進(jìn)行解碼,然后輸出就正常了~
# -*- coding:gbk -*-
d = {'name': '貝貝', 'age': 18}
json_str = json.dumps(d, encoding='gbk')
print type(json_str), '--', json_str
res_d = json.loads('{"age": 18, "name": "\u8d1d\u8d1d"}')
print type(res_d), '--', res_d
# 輸出結(jié)果:
<type 'str'> -- {"age": 18, "name": "\u8d1d\u8d1d"}
<type 'dict'> -- {u'age': 18, u'name': u'\u8d1d\u8d1d'}
注意:這里 loads 過程不需要指定編碼格式,因?yàn)榉葱蛄谢蟠娣诺絻?nèi)存中的依舊是unicode格式的字符串~
?
還有一種更簡單的解決方式,即在中文字符前加 u
d = {'name': u'貝貝', 'age': 18}
json_str = json.dumps(d)
pickle 模塊也用于序列化和反序列化Python對象(變量),其用法和 json 模塊的使用基本一致。pickle 模塊 和 json 模塊 區(qū)別在于:pickle 模塊 僅用于Python的數(shù)據(jù)類型,序列化后的對象不能再不同的編程語言之間傳遞,但是 pickle 模塊 可序列化幾乎所有的Python數(shù)據(jù)類型,包括時(shí)間對象,函數(shù),類…
?
import pickle
d = {'name': '貝貝', 'age': 18}
d_dump = pickle.dumps(d)
print(d_dump)
d_load = pickle.loads(d_dump)
print(type(d_load), '--', d_load)
# 結(jié)果輸出:
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x06\x00\x00\x00\xe8\xb4\x9d\xe8\xb4\x9dq\x02X\x03\x00\x00\x00ageq\x03K\x12u.' # 注意 輸出的是 byte 類型(即python2中的str類型)
<class 'dict'> -- {'name': '貝貝', 'age': 18}
####################################
lst = [1, 2, 3]
with open('/tmp/test_pickle', mode='wb') as f: # 打開文件的模式為二進(jìn)制寫
pickle.dump(lst, f)
with open('/tmp/test_pickle', mode='rb') as f: # 打開文件的模式為二進(jìn)制讀
lst_load = pickle.load(f)
print(type(lst_load), '--', lst_load)
# 結(jié)果輸出:
<class 'list'> -- [1, 2, 3]
# 存放序列化對象的文件:
? ~ cat /tmp/test_pickle
q(KKKe.%
可以看到 pickle序列化后的數(shù)據(jù),可讀性差,不像json那樣一目了然~
import pickle
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hello(self):
print('hello %s' % (self.name))
p = Person('貝貝', 18)
# p.say_hello()
# del Person
with open('/tmp/test_pickle', mode='wb') as f:
pickle.dump(p, f)
with open('/tmp/test_pickle', mode='rb') as f:
p_load = pickle.load(f)
p_load.say_hello()
# 輸出結(jié)果:
hello 貝貝
注意:中途不能del Person,不然會出現(xiàn)如下錯(cuò)誤
_pickle.PicklingError: Can't pickle <class '__main__.Person'>: attribute lookup Person on __main__ failed
shelve 模塊也用于序列化,shelve 模塊是在 pickle 模塊上做了一層封裝,也僅支持兩個(gè)Python程序之間進(jìn)行交換~,優(yōu)點(diǎn)是 shelve 模塊 可以序列化 Python 的所有數(shù)據(jù)類型~
?
shelve 模塊比 pickle 模塊更加簡單,只有一個(gè) open函數(shù),返回類似字典的對象,可讀可寫,當(dāng)為某個(gè) key 賦值時(shí),這個(gè)值會被序列化,并進(jìn)行存儲;通過某個(gè) key 讀出對應(yīng)的值時(shí),即是一個(gè)反序列化過程,其中 key 必須為字符串,而值可以是python所支持的數(shù)據(jù)類型。
?
shelve 模塊存取過程:
import shelve
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hello(self):
print('hello %s' % (self.name))
p = Person('貝貝', 18)
d = {'name': 'abc', 'age': 20}
f = shelve.open(r'/tmp/test_shelve')
f['d_info'] = d
f['p_info'] = p
print(f.get('d_info'))
f.get('p_info').say_hello()
f.close()
如上過程,class對象和基本數(shù)據(jù)類型會被序列化并存放在文件 '/tmp/test_shelve' 中,f.get() 取出過程即是一個(gè)反序列化過程~
?
若是一個(gè)可變對象,使用 shelve 模塊序列化之后存放到文件中,然后取出(get)對可變對象進(jìn)行更改,這個(gè)時(shí)候,已經(jīng)改變的可變對象只是保存在內(nèi)存中,不會被寫入到文件中,看如下示例:
import shelve
f = shelve.open(r'/tmp/test_shelve')
f['lst_info'] = [1,2,3]
f.get('lst_info').append(4)
print(f.get('lst_info'))
# 輸出結(jié)果:
[1, 2, 3]
若要進(jìn)行更改需要重新寫入,即重新序列化:
import shelve
f = shelve.open(r'/tmp/test_shelve')
f['lst_info'] = [1, 2, 3]
lst = f.get('lst_info')
lst.append(4)
f['lst_info'] = lst
print(f.get('lst_info'))
# 輸出結(jié)果:
[1, 2, 3, 4]
或者在使用 shelve 打開文件時(shí),設(shè)置 writeback 為True:
f = shelve.open(r'/tmp/test_shelve', writeback=True)
f['lst_info'] = [1, 2, 3]
f.get('lst_info').append(4)
print(f.get('lst_info'))
# 輸出結(jié)果:
[1, 2, 3, 4]
.................^_^
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
網(wǎng)站名稱:python序列化:json,pickle,shelve-創(chuàng)新互聯(lián)
本文鏈接:http://jinyejixie.com/article38/dpchsp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、網(wǎng)站建設(shè)、網(wǎng)站內(nèi)鏈、全網(wǎng)營銷推廣、微信公眾號、網(wǎng)站改版
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容