Python学习 Day 023 - 常用模块02

主要内容

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

 

posted @ 2018-10-09 19:18  一路向北_听风  阅读(328)  评论(0编辑  收藏  举报