主要内容
- 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格式数据
{
"name": "中国",
"province": [{
"name": "黑龙江",
"cities": {
"city": ["哈尔滨", "大庆"]
}
}, {
"name": "广东",
"cities": {
"city": ["广州", "深圳", "珠海"]
}
}, {
"name": "台湾",
"cities": {
"city": ["台北", "高雄"]
}
}, {
"name": "新疆",
"cities": {
"city": ["乌鲁木齐"]
}
}]
}
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"])