主要内容
- 1. 什么是序列化
- 2. pickle(重点)
- 3. shelve
- 4. json(重点)
- 5. configparser模块
1.序列化的概念
序列化:在我们存储数据或者网络传输数据的时候,需要对我们的对象进行处理,把对象处理成方便存储和传输的数据格式,这个过程叫序列化
不同的序列化, 结果也不同,但目的是一样的. 都是为了存储和传输.
在python中存在三种序列化的方案.
- pickle: 可以将我们python中的任意数据类型转化成bytes并写入到文件中,同样也可以把文件中写好的bytes转换回我们python的数据,这个过程被称为反序列化
- shelve: 另类的一种序列化的方案. 有点儿类似后面我们学到的redis,可以作为 一种小型的数据库来使用
- json: 将python中常见的字典, 列表转化成字符串,是目前后端数据交互使用频率最高的一种数据格式
2. pickle(重点)
pickle 就是把我们的python对象写入到文件中的一种解决方案. 但是写入到文件的是bytes. 所以这东西不是给人看的,是给机器看的.
import pickle
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def catchMouse(self):
print(self.name, self.age, "抓老鼠")
c = Cat("jerry",18)
bs = pickle.dumps(c) #序列化一个对象
print(bs) #一堆二进制,看不懂
cc = pickle.loads(bs) # 把二进制的反序列转化成我们的对象
cc.catchMouse() # 猫的功能可以执行
在pickle中的dumps可以序列化一个对象,loads可以反序列化一个对象
# c = Cat("jerry",18)
# f = open ("pickle1",mode="wb")
# pickle.dump(c,f) #结果人是无法查看的
# f.close()
f = open("pickle1",mode = "rb")
c = pickle.load(f)
print(c) #此时c是一个可执行对象
c.catchMouse()
# lst = [Cat("猫1", 10), Cat("猫2", 9), Cat("猫3", 8), Cat("猫4", 7), Cat("猫5", 6)]
# f = open("pickle1",mode = "wb")
# for el in lst:
# pickle.dump(el, f)
# f.flush()
# f.close()
f = open("pickle1",mode= "rb")
while 1:
try:
c = pickle.load(f)
c.catchMouse()
except EOFError:
break
在pickle中我们使用 dump 进行序列化,将对象转化成bytes并写入文件, load是反序列化,把文件中的bytes进行读取,转化成对象
但是这样写并不够好,因为读的时候,并不能知道有多少对象要读.这里记住, 不能一行一行的读. 那真的要写入或者读取多个内容怎么办? 很简单. 装list里. 然后读取和写入都用list
# lst = [Cat("猫1", 10), Cat("猫2", 9), Cat("猫3", 8), Cat("猫4", 7), Cat("猫5", 6)]
# f = open("pickle1",mode = "wb")
# pickle.dump(lst, f)
# f.flush()
# f.close()
f = open("pickle1",mode= "rb")
while 1:
try:
lst = pickle.load(f)
for el in lst :
el.catchMouse()
except EOFError:
break
3. shelve
shelve提供python的持久化操作. 持久化操作:就是把数据写到硬盘上,在操作shelve的时候非常的像操作一个字典,这个东西到后期,就像redis差不多
import shelve
f = shelve.open("sylar") #打开一个文件
f['Ljj'] = "林俊杰"
f['Jay'] = "周杰伦"
f['zzr'] = "周芷若" #像操作字典一样操作文件
print(f['Jay'])
print(f["Ljj"])
f.close()
# f = shelve.open("sylar")
# f["Jay"] = {"name":"周杰伦","age":"19","hobby":"唱歌"}
# print(f["Jay"])
# f.close()
# f = shelve.open("sylar")
# f["Jay"]["name"] = "肉夹馍"
# f.close()
#
# f = shelve.open("sylar")
# print(f["Jay"])
# f.close() #{'name': '周杰伦', 'age': '19', 'hobby': '唱歌'} 发现此时想要改变的值并未发生改变
#解决方案
f = shelve.open("sylar",writeback= True)
f["Jay"]["name"] = "肉夹馍"
f.close()
f = shelve.open("sylar")
print(f["Jay"])
f.close() #{'name': '肉夹馍', 'age': '19', 'hobby': '唱歌'}此时值发生改变
*** writeback=True可以动态的把我们修改的信息写入到文件中. 而且还可以删除数据,就像字典一样
# f = shelve.open("sylar",writeback=True)
# del f["Jay"]
# f.close()
#
# f = shelve.open("sylar")
# print(f["Jay"]) #报错,.没有了
# f.close()
# f = shelve.open("sylar", writeback=True)
# f['jay'] = "周杰伦"
# f['wlj'] = "王力宏"
# f.close()
# f = shelve.open("sylar")
# for k,v in f.items():
# print(k,v)
4. json(重点)
json概述
- json指的是JavaScript 对象表示法, json全称javascript object notation. 翻译过来叫js对象简谱.
- json是轻量级的文本数据交换格式
- json具有自我描述性,更易理解
- json使用javascript语法来描述数据对象,但json任然独立于语言和平台,json解析器和json库支持许多不同的编程语言
1.1 json的使用格式
- 合格的json对象
wf = {
"name": "汪峰",
"age": 18,
"hobby": "抢头条",
"wife": {
"name": "子怡",
"age": 19,
"hobby":["唱歌", "跳舞", "演戏"]
}
}
- 不合格的json对象
{ name: "张三", 'age': 32 } // 属性名必须使用双引号
[32, 64, 128, 0xFFF] // 不能使用十六进制值
{ "name": "张三", "age": undefined } // 不能使用undefined
{ "name": "张三",
"birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
"getName": function() {return this.name;} // 不能使用函数和日期对象
}
1.2 python环境中的json
- 在python里这玩意叫字典. 但是在javascript里这东西叫json
- 我们的程序是在python里写的,但是前端是在JS那边来解析json的,
- 所以,我们需要把我们程序产生的字典 转化成 json格式的json串(字符串),然后通过网络传输,那边接收到了之后,再进行传输.
(1)python中的json方法
- 需要将字典转化成json格式的字符串.
import json
dic = {"a":"少林足球","b":"大话西游","c":"功夫","d":"九品芝麻官"}
# s = json.dumps(dic) # 把字典转化成json字符串
# print(s) # {"a": "\u5c11\u6797\u8db3\u7403", "b": "\u5927\u8bdd\u897f\u6e38", "c": "\u529f\u592b", "d": "\u4e5d\u54c1\u829d\u9ebb\u5b98"}
# 如果你的key或者value超出了ascii范畴。 就会显示成\uxxxxx
s = json.dumps(dic,ensure_ascii=False) # 干掉ascii码
print(s,type(s)) #{"a": "少林足球", "b": "大话西游", "c": "功夫", "d": "九品芝麻官"},<class 'str'>
- 将前端传递过来的json字符串转化成字典
import json
#
dic = {"a":"少林足球","b":"大话西游","c":"功夫","d":"九品芝麻官"}
s = json.dumps(dic,ensure_ascii=False) # 干掉ascii码
dic1 = json.loads(s)
print(dic1,type(dic1)) #'a': '少林足球', 'b': '大话西游', 'c': '功夫', 'd': '九品芝麻官'} <class 'dict'>
- json也可以像pickle一样把序列化的结果写入到文件中
import json
# 写入
# dic = {"a":"少林足球","b":"大话西游","c":"功夫","d":"九品芝麻官"}
# f = open("json1",mode ="w",encoding ="utf-8")
# json.dump(dic,f,ensure_ascii=False) # 把json写入到文件中
# f.close()
#读出
f = open("json1",mode = "r",encoding = "utf-8")
s = json.load(f) #把文件中的json串读成字典
print(s,type(s)) #{'a': '少林足球', 'b': '大话西游', 'c': '功夫', 'd': '九品芝麻官'} <class 'dict'>
f.close()
- 另外:当向同一个文件写入json串时
import json
# lst = [{"a": 1}, {"b": 2}, {"c": 3}]
# #写入
# f = open("json2",mode = "w",encoding = "UTF-8")
# for el in lst:
# s = json.dumps(el,ensure_ascii=True) +"\n" #此处如果 写成json.dump(el, f, ensure_ascii=False)就写成了一行,读取时并不能够读出来
# f.write(s)
# f.close()
#读取
f = open("json2",mode= "r",encoding ="utf-8")
for line in f :
dic = json.loads(line.strip())
print(dic)
f.close()
(2) 小结
写入
- 循环
- 用dumps把字典转化成字符串, 然后手工在后面加一个\n
- 写入 f.write()
读取
- for line in f:
- strip()去掉空白
- loads()变成字典
1.3 stringify 与parse方法
JavaScript中关于JSON对象和字符串转换的两个方法:
- JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象
JSON.parse('{"name":"alex"}');
JSON.parse('{name:"alex"}') ; // 错误
JSON.parse('[18,undefined]') ; // 错误
- JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。
JSON.stringify({"name":"alex"})
1.4 和XML的比较
JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML 格式。
JSON 格式有两个显著的优点:书写简单,一目了然;符合 JavaScript 原生语法,可以由解释引擎直接处理,不用另外添加解析代码。所以,JSON迅速被接受,已经成为各大网站交换数据的标准格式,并被写入ECMAScript 5,成为标准的一部分。
XML和JSON都使用结构化方法来标记数据,下面来做一个简单的比较。
用XML表示中国部分省市数据如下:
<?xml version="1.0" encoding="utf-8"?>
<country>
<name>中国</name>
<province>
<name>黑龙江</name>
<cities>
<city>哈尔滨</city>
<city>大庆</city>
</cities>
</province>
<province>
<name>广东</name>
<cities>
<city>广州</city>
<city>深圳</city>
<city>珠海</city>
</cities>
</province>
<province>
<name>台湾</name>
<cities>
<city>台北</city>
<city>高雄</city>
</cities>
</province>
<province>
<name>新疆</name>
<cities>
<city>乌鲁木齐</city>
</cities>
</province>
</country>
XML格式数据
XML
{
"name": "中国",
"province": [{
"name": "黑龙江",
"cities": {
"city": ["哈尔滨", "大庆"]
}
}, {
"name": "广东",
"cities": {
"city": ["广州", "深圳", "珠海"]
}
}, {
"name": "台湾",
"cities": {
"city": ["台北", "高雄"]
}
}, {
"name": "新疆",
"cities": {
"city": ["乌鲁木齐"]
}
}]
}
JSON格式数据
json
由上面的两端代码可以看出,JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽
5. configparser模块
该模块适用于配置文件的格式与windows ini文件类,可以包含一个或多个节(section)每个节可以有多个参数(键=值)
[DEFAULT]
session-time-out = 30
user-alive = 60
connect-alive = 10
[189-DB]
ip = 189.135.63.12
port = 3306
uname = root
password = root
[166-DB]
ip = 189.135.63.12
port = 3306
uname = root
password = root
[163-DB]
ip = 189.135.63.12
port = 3306
uname = alex
password = root
wangermazi = 189
[jay]
import configparser
# conf = configparser.ConfigParser()
# conf["DEFAULT"] = {
# "session-time-out":30,
# "user-alive": 60,
# "connect-alive":10
# }
# conf["189-DB"] = {
# "ip": "189.135.63.12",
# "port": 3306,
# "uname": "root",
# "password": "root"
# }
# conf["166-DB"] = {
# "ip": "189.135.63.12",
# "port": 3306,
# "uname": "root",
# "password": "root"
# }
# conf["163-DB"] = {
# "ip": "189.135.63.12",
# "port": 3306,
# "uname": "root",
# "password": "root"
# }
#
# f = open("db.ini", mode="w")
# conf.write(f) # 把文件扔进去。 写到这个文件里
#读取
# conf = configparser.ConfigParser()
# conf.read("db.ini") #读取文件
# print(conf.sections()) # 获取到section. 章节...DEFAULT是给每个章节都配备的信息
# print(conf.get("DEFAULT","SESSION-TIME-OUT")) #从xxx章节中读取到xxx信息
#
# #可以像字典一样操作
# print(conf['166-DB']["ip"])
# print(conf["166-DB"]["port"])
# print(conf["166-DB"]["uname"])
# print(conf["166-DB"]["password"])
#
# for k,v in conf["166-DB"].items():
# print(k,v)
#增删改操作
conf = configparser.ConfigParser()
conf.read("db.ini") #读取出来
conf['163-DB']['uname'] = "alex"
# del conf['163-DB']["password"]
conf.set("163-DB", "wangermazi", "189")
conf.add_section("jay")
conf.write(open("db.ini", mode="w"))
Homework
1. 随机生成4位验证码(包含数字, 字母)
import random
lst = []
for el in range(48,58):
lst.append(chr(el))
for el in range(ord("a"),ord("z")):
lst.append(chr(el))
for el in range(ord("A"),ord("Z")):
lst.append(chr(el))
print(random.sample(lst,4))
# 关于题目:(1)random.sample(lst,n)的使用 (2)就是内置函数 ord()和chr()的使用
2. 模拟发红包. 不需要考虑权重问题,纯随机
例如:小红发了100块红包. 发给30人. 请给出每个人能收到的钱数
import random
def Redpacket(cash_total,share):
lst = []
money = 0
for i in range(share-1):
M = random.uniform(0,cash_total-money)
lst.append(M)
money+=M
lst.append(cash_total-money)
return lst
ret = Redpacket(100,30)
print(ret)
# 此种方式的随机极不均衡,大概率出现在前面,此种思维方式与秒杀类似(初始进来概率极大,此时秒杀与网速什么的无关)
#若使用递归
import random
lst=[]
def Redpacket(cash_total,share,money):
if cash_total > 0 and share!=1:
M = random.uniform(0,cash_total-money)
lst.append(M)
money+=M
share-=1
Redpacket(cash_total,share,money)
else:
lst.append(cash_total-money) #递归的出口是当只剩下最后一个人时,就分有此时最后一份钱,总数减去已经发出的钱
return lst
ret = Redpacket(100,30,0)
print(ret)
3.写一个用户注册登陆的程序,每一个用户的注册都要把用户名和密码通过pickle写入到文件中,在登陆的时候,再从文件中读取信息进行验证。
import pickle
class User:
def __init__(self,name,pwd):
self.name = name
self.pwd = pwd
class Document:
def __init__(self,file_name):
self.file_name = file_name
def Write(self,lst):
with open(self.file_name,mode = "wb") as f:
pickle.dump(lst,f)
def Read(self):
with open(self.file_name,mode = "rb") as f:
lst = pickle.load(f)
return lst
class Account:
def __init__(self):
pass
def register(self):
print("请注册账号和密码")
name,pwd = input("请输入注册名"),input("请输入密码")
u = User(name,pwd)
f=Document("user_info11")
lst = f.Read()
for el in lst:
if el.name == u.name:
print("您输入的注册名已被占用,请重新输入")
break
else:
lst.append(u)
f.Write(lst)
def login(self):
for i in range(2,-1,-1):
print("请用您的账号和密码进行登录")
username,password = input("请输入您的用户名"),input("请输入您的密码")
f = Document("user_info11")
lst = f.Read()
for el in lst:
if username == el.name and password == el.pwd:
return True
else:
print("登录失败,你还有%s次登录机会" % i)
def run(self):
while 1 :
print("1:注册 2:登录 3:退出")
num = int(input("请输入你要执行的操作:"))
if num ==1:
self.register()
elif num ==2:
if self.login():
print("登录成功,欢迎进入")
else:
print("登录失败")
elif num ==3:
print("程序退出中.....")
break
else:
print("你到底想干哈?")
lst = [User("张无忌",123),User("张三丰",456),User("成昆",789)] #首先在文件中创建一些账号信息
f = Document("user_info11")
f.Write(lst)
obj = Account()
obj.run()
4.请从以下网址获取json数据. 并对json进行分析. 获取到每家店的名称以及特色菜, 并把获取到的店名和特色菜写入到文件中:
浏览器输入网址打开网站,当获取到 resturant link address ,然后获取店铺及其特色菜(你自己输入)
温馨提示. 首先在chrome地址栏中输入以上网址. 然后把显示的所有内容复制. 按F12 找到屏幕中的console. 粘贴进去. 回车 就能看到数据了.此题需要用到urllib.request模块中的urlopen
import json
from urllib.request import urlopen
content = urlopen("https://h5.ele.me/restapi/shopping/v2/restaurants/search?offset=60&limit=15&keyword=%E7%82%92%E9%9D%A2&latitude=39.89491&longitude=116.322056&search_item_type=3&is_rewrite=1&extras[]=activities&extras[]=coupon&terminal=h5").read()
s = content.decode("utf-8")
dic = json.loads(s)
rwf = dic["inside"]["0"]["restaurant_with_foods"]
for el in rwf:
print(el["restaurant"]["name"])
for food in el["foods"]:
print(food["name"])