zoukankan      html  css  js  c++  java
  • 🍖json 模块

    引入

    1.eval( ) 函数

    • 内置函数 这一张中我们介绍过了 eval( ) 函数, 他可以将字符串转成Python对象
    • 不过局限性比较大, 只能运用于普通的数据类型, 遇到特殊的数据类型就不管用 了
    • eval( ) 的处理重点 : 执行一个字符串表达式, 并返回表达式的值

    2.eval 函数存取数据示例

    通过文件将字典转成字符串存入(序列化)
    dic = {'name':'egon','age':18}
    with open('db.txt','w',encoding='utf-8')as f :
        f.write(str(dic))
        
    通过"eval"函数将拿出来的字符串转成数据结构(反序列化)
    with open('db.txt','r',encoding='utf-8')as f:
        data = f.read()
        dic = eval(data)
        print(dic)        # {'name': 'egon', 'age': 18}
        print(type(dic))  # <class 'dict'>
    

    3.eval 的局限性

    x="[null,true,false,1]"
    print(eval(x))  # 报错,无法解析null类型
    

    一.什么是序列化和反序列化

    1.序列化

    • 把某个语言的变量转成 json 格式字符串

    • 内存中的数据结构----->转成一种中间格式(字符串)----->存到文件中

    2.反序列化

    • json 格式字符串转成某个语言的变量

    • 文件----->读取中间格式(字符串)----->转成内存中数据结构

    3.json 的标准格式字符串

    • {"name" : "shawn", "age" : 18, "local" : true, "xx" : null}
    • json格式字符串符号必须是双引号

    二.为什么要序列化

    序列化两种用途:

    1.持久保持状态

    • 一个软件或程序的运行就是在处理一系列状态的变化, 编程语言中, "状态"会以各种各样有结构的数据类型(或变量)保存在内存中
    • 而内存是无法永久保存数据的, 当断电或者是重启程序, 内存中那些有结构的数据都会被清空
    • 那么序列化就是在你机器在断电或重启之前将当前内存中的数据都保存到文件中去,下次执行程序可以直接载入之前的数据, 然后继续执行 (就相当于单机游戏存档)

    存取数据的格式标准, 一个程序写入, 另一个程序读取 (这两个程序可以是使用不同的语言写的)

    2.跨平台数据交互

    • 序列化之后, 不仅可以将序列化后的内容存入磁盘, 也可以通过网络传输到别的机器上
    • 如果发送和接收方都约定好使用同一种序列化的格式, 那么便屏蔽了平台和语言所带来的的差异性, 实现了跨平台数据交互
    • 反过来, 把数据(变量)内容从序列化的对象重新读到内存中, 这就称之为反序列化

    例如 : 后端给前端的数据就是 "json" 格式字符串

    三. json 能序列化的类型

    • json 模块可以序列化:字典,列表,布尔

    • json 数据类型和 python 数据类型对应关系表

    Json类型 Python类型
    {} dict
    [] list
    "string" str
    1.73 int或float
    true/false True/False
    null None
    • 序列化三种类型示例 (简单使用方法)
    dic = {'movieIds': [111, 222, 333, 444],\
    	'stids': [{'movieId': 11, 'stid': 1}, \
    				{'movieId': 22, 'stid': 2}, \
    					{'movieId': 33, 'stid': 3}]}
    res = json.dumps(dic)
    print(res)  
    '''可以发现对应格式已经发生了转变
    {"movieIds": [111, 222, 333, 444],\
    "stids": [{"movieId": 11, "stid": 1},{"movieId": 22, "stid": 2}, {"movieId": 33, "stid": 3}]}
    '''                          	
    

    四.json 序列化的使用

    1.简单用法

    import json
    
    dic = {"name":"song"}
    print(json.dumps(dic))  # {"name": "song"}
    
    s = '{"name": "song"}'
    print(json.loads(s))  # {'name': 'song'}
    

    2.写入文件序列化与反序列化 (复杂)

    • 序列化 : .dumps()
    import json
    
    dic = {'name':'song','age':21}
    dic = json.dumps(dic)
    print(dic,type(dic))  # {"name": "song", "age": 21} <class 'str'>
    with open('db.json','a',encoding='utf-8')as f:
        f.write(dic)
    
    • 反序列化 : .loads()
    with open('db.json', 'rt', encoding='utf-8')as f:
        data = f.read()
        dic = json.loads(data)
        print(dic, type(dic))  # {'name': 'song', 'age': 21} <class 'dict'>
    

    3.简单序列化与反序列化 (提供直接写入文件功能)

    • 序列化 : .dump()
    • 直接以字符串写进文件
    import json
    dic = {'name':'song','age':21}
    with open('db1.json','wt',encoding='utf-8')as f:
        json.dump(dic,f) 
    
    • 反序列化 : .load()
    • 直接拿出来转成你的数据类型
    with open('db1.json','rt',encoding='utf-8')as f:
        dic = json.load(f)
        print(dic,dic['age'])  # {'name': 'song', 'age': 21} 21
    

    五.中文序列化问题

    • 演示
    import json
    
    dic = {"name": "派大星", "age": 22}
    res = json.dumps(dic)
    print(res)  # {"name": "\u6d3e\u5927\u661f", "age": 22}
    
    • 加入 ensure_ascii=False 功能
    dic = {"name": "派大星", "age": 22}
    res = json.dumps(dic,ensure_ascii=False)
    print(res)  # {"name": "派大星", "age": 22}
    
    • 问题总结
    并没有使用上的变化, 存的是什么, 取出来的还是什么, 只不过人家内部帮你转成"uncode"格式保存
    

    ps : java中,出于性能的考虑,有很多包来完成序列化和反序列化:谷歌的gson 阿里开源fastjson 等等

    六.猴子补丁

    1.什么是猴子补丁

    • 运行时动态的修改模块, 类, 函数, 通常是添加功能或修正缺陷

    • 猴子补丁在代码运行内存中发挥作用, 不会修改源代码, 因此只在运行时有效

    猴子补丁(Monkey Patch)

    这个词原来为Guerrilla Patch,杂牌军、游击队,说明这部分不是原装的,在英文里guerilla发音和gorllia(猩猩)相似,再后来就写了monkey(猴子)

    还有一种解释是说由于这种方式将原来的代码弄乱了(messing with it),在英文里叫monkeying about(顽皮的),所以叫做Monkey Patch

    2.猴子补丁的功能演示

    一切皆对象, 拥有模块, 类, 函数运行时替换的功能

    一个函数对象赋值给另一个函数对象

    将函数原本执行的功能替换掉了

    class aaa:
        def bbb(self):
            print("i am bbb")
    
        def ccc(self):
            print("i am ccc")
    
    def ddd():
        print("i am ddd")
    
    AAA = aaa()
    AAA.bbb = AAA.ccc
    AAA.bbb()  # i am ccc
    
    AAA.ccc = ddd
    AAA.ccc()  # i am ddd
    

    3.猴子补丁的应用场景

    如果我们基于 json 模块写了大量的代码, 然后发现 ujson 比它快10倍, 并且用法一样

    我们肯定不会想到把所有的 json.dumps或 json.loads 全换成 ujson.dumps或 ujson.loads

    我们可能会想到 模块取别名 import json as ujson, 但这样每个模块都需要重新导入一下

    以上方法的维护成本都非常高, 此时我们就可以使用到猴子补丁了, 只需要在入口文件加上就行

    import json
    import ujson
    
    def monkey_patch_json():
    	json.__name__ = 'ujson'
    	json.dumps = ujson.dumps
    	json.loads = ujson.loads
    	
    monket_patch_json()
    

    4.猴子补丁优缺点总结

    之所以在入口处加, 是因为模块在导入一次之后, 后续的导入变直接引用第一次导入的结果

    其实这种场景也比较多, 比如我们引用团队通用库里的一个模块, 又想丰富模块的功能, 除了继承之外也可以考虑用Monkey Patch

    优点 : 采用猴子补丁后, 如果发现 ujson 不符合预期, 那也可以快速撤回补丁

    缺点 : 因为Monkey Patch破坏了封装, 带来了搞乱源代码的风险

    六.pickle 模块

    pickle序列化与反序列化点我

  • 相关阅读:
    PHP大文件上传断点续传源码
    PHP大文件上传断点续传解决方案
    Flash大文件断点续传解决方案
    Flash大文件断点续传功能
    ASP.NET上传断点续传
    B/S文件上传下载解决方案
    web文件夹上传下载方案
    Codeforces 460E Roland and Rose(暴力)
    iOS_25_彩票骨架搭建+导航栏适配
    配置Redmine的邮件通知功能
  • 原文地址:https://www.cnblogs.com/songhaixing/p/14135928.html
Copyright © 2011-2022 走看看