常用模块-02
本节主要内容:
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'\x80\x03c__main__\nCat\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x # 03X\x05\x00\x00\x00Jerryq\x04X\x03\x00\x00\x00ageq\x05K\x12ub.' 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) + "\n" 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"))