本節主要內容:
1. 什麼是序列化
2.pickle(重點)
3.shelve
4.json(重點)
5.configparser模組
一. 什麼是序列化
在我們儲存資料或者網路傳輸資料的時候.需要對我們的物件進行處理.把物件處理成方便儲存和傳輸的資料格式.
這個過程叫序列化.不同的序列化,結果也不同.但是目的是一樣的.都是為了儲存和傳輸.
在python中存在三種序列化的方案:
1.pickle:可以將我們python中的任意資料型別轉化成bytes並寫入到檔案中.同樣也可以把檔案中寫好的bytes轉換回我們
python的資料.這個過程被稱為反序列化
2.shelve:簡單另類的一種序列化的方案,有點類似後面會學到的redis,可以作為一種小型的資料庫來使用
3.json:將python中常見的字典,列表轉化成字串,是目前後端資料互動使用頻率最高的一種資料格式.
二.pickle(重點)
pickle: 可以將我們python中的任意資料型別轉化成bytes並寫入到檔案中.同樣也可以把檔案中寫好的bytes轉換回我們python
的資料.這個過程被稱為反序列化.
pickle.dumps(c) & pickleloads
import pickle class Cat: def __init__(self,name,age): self.name = name self.age = age def chi(self): print(self.name, "抓老鼠") c = Cat("Jerry",18) bs = pickle.dumps(c) # 序列化一個物件. print(bs) # 一堆二進位制 # b`x80x03c__main__ Cat qx00)x81qx01}qx02(Xx04x00x00x00nameqx # 03Xx05x00x00x00Jerryqx04Xx03x00x00x00ageqx05Kx12ub.` cc = pickle.loads(bs) # 把二進位制反序列化成我們的物件 cc.chi() # 依舊是之前的物件 # Jerry 抓老鼠
pickle中的dumps可以序列化一個物件.loads可以反序列化一個物件.
pickle.dump() & pickle.load()
import pickle class Cat: def __init__(self,name,age): self.name = name self.age = age def chi(self): print(self.name, "抓老鼠") c = Cat("Jerry",18) f1 = open("cat",mode="wb") pickle.dump(c,f1) # 寫入到檔案中 f1.close() f2 = open("cat",mode="rb") cc = pickle.load(f2) # 從檔案中讀取物件 cc.chi()
dump可以直接把一個物件寫入到檔案中,load可以從檔案中讀取物件
pickle還支援多個物件的寫入
import pickle class Cat: def __init__(self,name,age): self.name = name self.age = age def chi(self): print(self.name, "抓老鼠") lst = [Cat("Jerry", 19), Cat("Tommy", 20), Cat("alpha", 21)] with open("cat", mode="wb") as f3: for el in lst: pickle.dump(el,f3) # 寫入到檔案中 with open ("cat", mode="rb") as f4: for i in range(len(lst)): cc = pickle.load(f4) # 從檔案中讀取物件 cc.chi()
但是有的時候我們並不知道我們有多少物件需要讀. 這裡記住,不能一行一行的讀, 因為假如要讀的內容有很多怎麼辦?
多以我們可以把要讀的檔案裝在list裡, 然後讀取和寫入都用list
import pickle class Cat: def __init__(self,name,age): self.name = name self.age = age def chi(self): print(self.name, "抓老鼠") lst = [Cat("Jerry", 19), Cat("Tommy", 20), Cat("alpha", 21)] with open("cat.dat", mode="wb") as f3: pickle.dump(lst,f3) f = open("cat.dat", mode="rb") lst = pickle.load(f) # 讀取第一次 for el in lst: el.chi()
在使用pickle的時候,記住pickle序列化的內容是二進位制的內容(bytes).
三.shelve
shelve提供python的持久化操作. 持久化操作就是把資料寫到硬碟上.在操作shelve的時候非常像操作一個字典.
shelve:簡單另類的一種序列化的方案,有點類似後面會學到的redis,可以作為一種小型的資料庫來使用
import shelve shelf = shelve.open("sylar") # shelf["jay"] = "周杰倫" print(shelf[`jay`]) shelf.close()
接下來我們可以儲存一點複雜的資料
s = shelve.open("sylar") # s["jay"] = {"name":"周杰倫", "age":18, "hobby":"哄⼩孩"} print(s[`jay`]) s.close()
但是當我們嘗試去改變字典中的資料的時候,會發現有問題
s = shelve.open("sylar") s[`jay`][`name`] = "胡辣湯" # 嘗試改變字典中的資料 s.close() s = shelve.open("sylar") print(s[`jay`]) # 並沒有改變 s.close()
解決方案:
s = shelve.open("sylar", writeback=True) s[`jay`][`name`] = "胡辣湯" # 嘗試改變字典中的資料 s.close() s = shelve.open("sylar") print(s[`jay`]) # 改變了. s.close()
writeback=True可以動態的把我們修改的資訊寫入到⽂件中. ⽽且它還可以刪 除資料. 就像字典⼀樣.
s = shelve.open("sylar", writeback=True) del s[`jay`] s.close() s = shelve.open("sylar") print(s[`jay`]) # 報錯了, 沒有了 s.close() s = shelve.open("sylar", writeback=True) s[`jay`] = "周杰倫" s[`wlj`] = "王⼒巨集" s.close() s = shelve.open("sylar") for k in s: # 像字典⼀樣遍歷 print(k) print(s.keys()) # 拿到所有key的集合 for k in s.keys(): print(k) for k, v in s.items(): # 像字典⼀樣操作 print(k, v) s.close()
綜上,我們把shelve當成字典來用就好了
四.json(重點)
json: JavaScript Object Notation JS物件簡譜
因為json的語法格式可以完美的表⽰出⼀個物件.
json:前後端互動的樞紐,相當於程式設計界的普通話.為什麼大家都用json來溝通呢?因為json的語法格式可以完美的表⽰出⼀個物件.
wf = { "name":"汪峰", "age":18, "hobby":"上頭條", "wife":{ "name":`⼦怡`, "age":19, "hobby":["唱歌", "跳舞", "演戲"] } }
在python中上面的內容叫做字典,但是在JavaScript中上面的內容被叫做json.這樣的資料結構可以完美的表示出任何物件.
並且可以完整的把物件表示出來,而且只要程式碼格式比較好,可讀性也很強.所以大家公認用這樣一種資料結構作為資料交
互的格式.而在這之前的程式設計師使用一種叫做XML的東西.
<?xml version="1.0" encoding="utf-8" ?> <wf> <name>汪峰</name> <age>18</age> <hobby>上頭條</hobby> <wife> <name>⼦怡</name> <age>18</age> <hobbies> <hobby>唱歌</hobby> <hobby>跳舞</hobby> <hobby>演戲</hobby> </hobbies> </wife> </wf>
以前的程式設計師都是用上面這樣的資料進行傳輸的,老版本的xml在維護和處理上是非常複雜和繁瑣的,而且解析比較複雜.
1.字典==>json字串 json字串==>字典
import json dic = {"a": "女王", "b": "蘿莉", "c":"小清新"} s = json.dumps(dic, ensure_ascii=False) # 把字典轉換成json字串 print(s) # 結果:{"a": "女王", "b": "蘿莉", "c": "小清新"}
ensure_ascii = False 的作用是不使用ASCII來解碼, 因為我們的內容中有中文
import json s = `{"a": "女王", "b": "蘿莉", "c": "小清新"}` dic = json.loads(s) print(type(dic), dic) # 結果:<class `dict`> {`a`: `女王`, `b`: `蘿莉`, `c`: `小清新`}
json也可以像pickle一樣把序列化的結果寫入到檔案中
import json dic = {"a": "女王", "b": "蘿莉", "c": "小清新"} with open("abc.json", mode="w", encoding="utf-8") as f: json.dump(dic, f, ensure_ascii=False)
從檔案中讀取一個json檔案
import json with open("abc.json", mode="r", encoding="utf-8") as f: dic = json.load(f) print(dic)
注意: 我們可以向同一個檔案中寫入多個json串. 但是讀不行
import json lst = [{"a": 1}, {"b": 2}, {"c": 3}] with open("lst.json", mode="w", encoding="utf-8") as f: for el in lst: json.dump(el,f)
注意,此時檔案中的內容是一行內容.
{"a": 1}{"b": 2}{"c": 3}
這在讀取的時候是⽆法正常讀取的. 那如何解決呢? 兩套⽅案. ⽅案⼀. 把所有的內容準備好統⼀進⾏寫⼊和讀取.
但這樣處理, 如果資料量⼩還好. 資料量⼤的話, 就不夠友好了. ⽅案⼆. 不⽤ dump. 改⽤dumps和loads. 對每⼀⾏分別進⾏處理.
import json lst = [{"a": 1}, {"b": 2}, {"c": 3}] # 寫入 f = open("lst.json", mode="w", encoding="utf-8") for el in lst: s = json.dumps(el,ensure_ascii=True) + " " f.write(s) f.close() # 讀取 f = open("lst.json", mode="r",encoding="utf-8") for line in f: dic = json.loads(line.strip()) print(dic) f.close()
五.configparser模組
該模組適⽤於配置⽂件的格式與windows ini⽂件類似,可以包含⼀個或多個節(section)每個節可以有多個引數(鍵=值).
⾸先, 我們先看⼀個xxx伺服器的配置⽂件
[DEFAULT] [DEFAULT] ServerAliveInterval = 45 Compression = yes CompressionLevel = 9 ForwardX11 = yes
[[bitbucket.org bitbucket.org]] User = hg
[[topsecret.server.com topsecret.server.com]] Port = 50022 ForwardX11 = no
我們用configparser就可以對這樣的檔案進行處理,首先是初始化
import configparser config = configparser.ConfigParser() config[`DEFAULT`] = { "sleep": 1000, "session-time-out": 30, "user-alive": 999999 } config[`TEST-DB`] = { "db_ip": "192.168.17.189", "port": "3306", "u_name": "root", "u_pwd": "123456" } config[`168-DB`] = { "db_ip": "152.163.18.168", "port": "3306", "u_name": "root", "u_pwd": "123456" } config[`173-DB`] = { "db_ip": "152.163.18.173", "port": "3306", "u_name": "root", "u_pwd": "123456" } f = open("db.ini", mode="w") config.write(f) # 寫⼊⽂件 f.flush() f.close()
讀取檔案資訊:
config = configparser.ConfigParser() config.read("db.ini") # 讀取⽂件 print(config.sections()) # 獲取到section. 章節...DEFAULT是給每個章節都配備的資訊 print(config.get("DEFAULT", "SESSION-TIME-OUT")) # 從xxx章節中讀取到xxx資訊 # 也可以像字典⼀樣操作 print(config["TEST-DB"][`DB_IP`]) print(config["173-DB"]["db_ip"]) for k in config[`168-DB`]: print(k) for k, v in config["168-DB"].items(): print(k, v) print(config.options(`168-DB`)) # 同for迴圈,找到`168-DB`下所有鍵 print(config.items(`168-DB`)) #找到`168-DB`下所有鍵值對 print(config.get(`168-DB`,`db_ip`)) # 152.163.18.168 get⽅法Section下的 key對應的value
增刪改操作:
# 先讀取. 然後修改. 最後寫回⽂件 config = configparser.ConfigParser() config.read("db.ini") # 讀取⽂件 # 新增⼀個章節 # config.add_section("189-DB") # config["189-DB"] = { # "db_ip": "167.76.22.189", # "port": "3306", # "u_name": "root", # "u_pwd": "123456" # } # 修改資訊 config.set("168-DB", "db_ip", "10.10.10.168") # 刪除章節 config.remove_section("173-DB") # 刪除元素資訊 config.remove_option("168-DB", "u_name") # 寫回⽂件 config.write(open("db.ini", mode="w"))