常用模組-02

AF1y發表於2018-11-16

本節主要內容:

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"))

 

相關文章