簡(jiǎn)介
什么是序列化
序列化 (Serialization):將對(duì)象的狀態(tài)信息轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)男问降倪^程。
即:把對(duì)象(變量)從內(nèi)存中變成可存儲(chǔ)或傳輸?shù)倪^程稱之為序列化栓始。
在Python中叫pickling务冕,在其他語言中也被稱之為serialization,marshalling幻赚,flattening等等禀忆,都是一個(gè)意思。
為什么要序列化落恼?
1:持久保存狀態(tài)
需知一個(gè)軟件/程序的執(zhí)行就在處理一系列狀態(tài)的變化箩退,在編程語言中,'狀態(tài)'會(huì)以各種各樣有結(jié)構(gòu)的數(shù)據(jù)類型(也可簡(jiǎn)單的理解為變量)的形式被保存在內(nèi)存中佳谦。
內(nèi)存是無法永久保存數(shù)據(jù)的戴涝,當(dāng)程序運(yùn)行了一段時(shí)間,我們斷電或者重啟程序,內(nèi)存中關(guān)于這個(gè)程序的之前一段時(shí)間的數(shù)據(jù)(有結(jié)構(gòu))都被清空了喊括。
在斷電或重啟程序之前將程序當(dāng)前內(nèi)存中所有的數(shù)據(jù)都保存下來(保存到文件中)胧瓜,以便于下次程序執(zhí)行能夠從文件中載入之前的數(shù)據(jù),然后繼續(xù)執(zhí)行郑什,這就是序列化府喳。
具體的來說,你玩使命召喚闖到了第13關(guān)蘑拯,你保存游戲狀態(tài)钝满,關(guān)機(jī)走人,下次再玩申窘,還能從上次的位置開始繼續(xù)闖關(guān)弯蚜。或如剃法,虛擬機(jī)狀態(tài)的掛起等碎捺。
2:跨平臺(tái)數(shù)據(jù)交互
序列化之后,不僅可以把序列化后的內(nèi)容寫入磁盤贷洲,還可以通過網(wǎng)絡(luò)傳輸?shù)絼e的機(jī)器上收厨,如果收發(fā)的雙方約定好實(shí)用一種序列化的格式,那么便打破了平臺(tái)/語言差異化帶來的限制优构,實(shí)現(xiàn)了跨平臺(tái)數(shù)據(jù)交互诵叁。
反過來,把變量內(nèi)容從序列化的對(duì)象重新讀到內(nèi)存里稱之為反序列化钦椭,即unpickling拧额。
如何序列化之json和pickle
json
import json
#---------------------序列化-------------------
dic = {'name':'alvin','age':23,'sex':'male'}
print(type(dic)) #<class 'dict'>
j=json.dumps(dic)
print(type(j))#<class 'str'>
f=open('序列化對(duì)象','w')
f.write(j) #等價(jià)于json.dump(dic,f)
f.close()
#-----------------------------反序列化
import json
f=open('序列化對(duì)象')
data=json.loads(f.read())# 等價(jià)于data=json.load(f)
注意:
import json
#dct="{'1':111}"#json 不認(rèn)單引號(hào)
#dct=str({"1":111})#報(bào)錯(cuò),因?yàn)樯傻臄?shù)據(jù)還是單引號(hào):{'one': 1}
dct='{"1":"111"}'
print(json.loads(dct))
#conclusion:
# 無論數(shù)據(jù)是怎樣創(chuàng)建的,只要滿足json格式彪腔,就可以json.loads出來,不一定非要dumps的數(shù)據(jù)才能loads
pickle
import pickle
#-------------------------序列化
dic={'name':'alvin','age':23,'sex':'male'}
print(type(dic))#<class 'dict'>
j=pickle.dumps(dic)
print(type(j))#<class 'bytes'>
f=open('序列化對(duì)象_pickle','wb')#注意是w是寫入str,wb是寫入bytes,j是'bytes'
f.write(j) #等價(jià)于pickle.dump(dic,f)
f.close()
#-------------------------反序列化
import pickle
f=open('序列化對(duì)象_pickle','rb')
data=pickle.loads(f.read())# 等價(jià)于data=pickle.load(f)
print(data['age'])
Pickle的問題和所有其他編程語言特有的序列化問題一樣侥锦,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容漫仆,因此捎拯,只能用Pickle保存那些不重要的數(shù)據(jù),不能成功地反序列化也沒關(guān)系盲厌。
shelve
shelve模塊比pickle模塊簡(jiǎn)單,只有一個(gè)open函數(shù)祸泪,返回類似字典的對(duì)象吗浩,可讀可寫;key必須為字符串,而值可以是python所支持的數(shù)據(jù)類型
import shelve
f=shelve.open(r'sheve.txt')
# f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
# f['stu2_info']={'name':'gangdan','age':53}
# f['school_info']={'website':'http://www.pypy.org','city':'beijing'}
print(f['stu1_info']['hobby'])
f.close()
xml
xml是實(shí)現(xiàn)不同語言或程序之間進(jìn)行數(shù)據(jù)交換的協(xié)議没隘,跟json差不多懂扼,但json使用起來更簡(jiǎn)單。
xml的格式如下,就是通過<>節(jié)點(diǎn)來區(qū)別數(shù)據(jù)結(jié)構(gòu)的:
xml數(shù)據(jù)
<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
xml協(xié)議在各個(gè)語言里的都 是支持的阀湿,在python中可以用以下模塊操作xml:
# print(root.iter('year')) #全文搜索
# print(root.find('country')) #在root的子節(jié)點(diǎn)找赶熟,只找一個(gè)
# print(root.findall('country')) #在root的子節(jié)點(diǎn)找,找所有
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
#遍歷xml文檔
for child in root:
print('========>',child.tag,child.attrib,child.attrib['name'])
for i in child:
print(i.tag,i.attrib,i.text)
#只遍歷year 節(jié)點(diǎn)
for node in root.iter('year'):
print(node.tag,node.text)
#---------------------------------------
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
#修改
for node in root.iter('year'):
new_year=int(node.text)+1
node.text=str(new_year)
node.set('updated','yes')
node.set('version','1.0')
tree.write('test.xml')
#刪除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
#在country內(nèi)添加(append)節(jié)點(diǎn)year2
import xml.etree.ElementTree as ET
tree = ET.parse("a.xml")
root=tree.getroot()
for country in root.findall('country'):
for year in country.findall('year'):
if int(year.text) > 2000:
year2=ET.Element('year2')
year2.text='新年'
year2.attrib={'update':'yes'}
country.append(year2) #往country節(jié)點(diǎn)下添加子節(jié)點(diǎn)
tree.write('a.xml.swap')
自己創(chuàng)建xml文檔:
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'
et = ET.ElementTree(new_xml) #生成文檔對(duì)象
et.write("test.xml", encoding="utf-8",xml_declaration=True)
ET.dump(new_xml) #打印生成的格式