zoukankan      html  css  js  c++  java
  • 第十二天——序列化模块(八)

    一. 序列化模块

    我们今天学习下序列化,什么是序列化呢? 序列化的本质就是将一种数据结构(如字典、列表)等转换成一个特殊的序列(字符串或者bytes)的过程就叫做序列化。那么有同学就会问了,为什么要转化成这个序列,我们不是学过么?

    dic = {'name': '郭宝元'}
    ret = str(dic)
    print(ret,type(ret))
    

    首先你要看清楚!我说的是一个特殊的序列,而不是我们常用的str这种字符串。

    为什么要有序列化模块?

    其次,将这个数据结构转化成这个特殊的序列有什么用呢? 这个才是序列化的关键所在,这个特殊的序列大有用处。举例说明:

    比如,你的程序中需要一个字典类型的数据存放你的个人信息:

     dic = {'username':'宝元', 'password': 123,'login_status': True}
    

      你的程序中有一些地方都需要使用这个dic数据,登录时会用到,注册时也会用到。那么我们之前就是将这个dic写在全局里,但是这样是不合理的,应该是将这数据写入一个地方存储(还没有学数据库)先存放在一个文件中,那么程序中哪里需要这个数据了,你就读取文件取出你需要的信息即可。那么有没有什么问题? 你将这个字典直接写入文件是不可以的,必须转化成字符串的形式,而且你读取出来也是字符串形式的字典(可以用代码展示)。

    那么你拿到一个str(dic)有什么用?他是根本转化不成dic的(不能用eval很危险),所以很不方便。那么这时候序列化模块就起到作用了,如果你写入文件中的字符串是一个序列化后的特殊的字符串,那么当你从文件中读取出来,是可以转化回原数据结构的。这个就很牛逼了。

    下面说的是json序列化,pickle序列化有所不同。

    json序列化除了可以解决写入文件的问题,还可以解决网络传输的问题,比如你将一个list数据结构通过网络传给另个开发者,那么你不可以直接传输,之前我们说过,你要想传输出去必须用bytes类型。但是bytes类型只能与字符串类型互相转化,它不能与其他数据结构直接转化,所以,你只能将list ---> 字符串 ---> bytes 然后发送,对方收到之后,在decode() 解码成原字符串。此时这个字符串不能是我们之前学过的str那种字符串,因为它不能反解,必须要是这个特殊的字符串,他可以反解成list 这样开发者之间就可以借助网络互传数据了,不仅仅是开发者之间,你要借助网络爬取数据这些数据多半是这种特殊的字符串,你接受到之后,在反解成你需要的数据类型。

    对于这个序列化模块我们做一个小小总结:

    序列化模块就是将一个常见的数据结构转化成一个特殊的序列,并且这个特殊的序列还可以反解回去。它的主要用途:文件读写数据,网络传输数据。

    Python中这种序列化模块有三种:

    ​ json模块 :(重点

    1. 不同语言都遵循的一种数据转化格式,即不同语言都使用的特殊字符串。(比如Python的一个列表[1, 2, 3]利用json转化成特殊的字符串,然后在编码成bytes发送给php的开发者,php的开发者就可以解码成特殊的字符串,然后在反解成原数组(列表): [1, 2, 3])

    2. json序列化只支持部分Python数据结构:dict,list, tuple,str,int, float,True,False,None

    ​ pickle模块:

    1. 只能是Python语言遵循的一种数据转化格式,只能在python语言中使用。

    2. 支持Python所有的数据类型包括实例化对象。

    ​ shelve模块:类似于字典的操作方式去操作特殊的字符串(不讲,可以课下了解)。

    当然序列化模块中使用最多的的就是json模块,那么接下来,我们讲一下json与pickle模块。

    1.1 json模块

    json模块是将满足条件的数据结构转化成特殊的字符串,并且也可以反序列化还原回去。

    上面介绍我已经说过了,序列化模块总共只有两种用法,要不就是用于网络传输的中间环节,要不就是文件存储的中间环节,所以json模块总共就有两对四个方法:

    用于网络传输:dumps、loads

    用于文件写读:dump、load

    dumps、loads

    1. 将字典类型转换成字符串类型
    import json
    dic = {'k1':'v1','k2':'v2','k3':'v3'}
    str_dic = json.dumps(dic)  #序列化:将一个字典转换成一个字符串
    print(type(str_dic),str_dic)  #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}
    #注意,json转换完的字符串类型的字典中的字符串是由""表示的
    
    1. 将字符串类型的字典转换成字典类型
    import json
    dic2 = json.loads(str_dic)  #反序列化:将一个字符串格式的字典转换成一个字典
    #注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示
    print(type(dic2),dic2)  #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
    
    1. 还支持列表类型
    list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]
    str_dic = json.dumps(list_dic) #也可以处理嵌套的数据类型 
    print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]
    list_dic2 = json.loads(str_dic)
    print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]
    

    dump、load

    1. 将对象转换成字符串写入到文件当中
    import json
    f = open('json_file.json','w')
    dic = {'k1':'v1','k2':'v2','k3':'v3'}
    json.dump(dic,f)  #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
    f.close()
    # json文件也是文件,就是专门存储json字符串的文件。
    
    1. 将文件中的字符串类型的字典转换成字典
    import json
    f = open('json_file.json')
    dic2 = json.load(f)  #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
    f.close()
    print(type(dic2),dic2)
    

    其他参数说明

    ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。

    separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(,,:);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。

    sort_keys:将数据根据keys的值进行排序。 剩下的自己看源码研究

    json序列化存储多个数据到同一个文件中

    对于json序列化,存储多个数据到一个文件中是有问题的,默认一个json文件只能存储一个json数据,但是也可以解决,举例说明:

    对于json 存储多个数据到文件中
    dic1 = {'name':'oldboy1'}
    dic2 = {'name':'oldboy2'}
    dic3 = {'name':'oldboy3'}
    f = open('序列化',encoding='utf-8',mode='a')
    json.dump(dic1,f)
    json.dump(dic2,f)
    json.dump(dic3,f)
    f.close()
    

    f = open('序列化',encoding='utf-8')
    ret = json.load(f)
    ret1 = json.load(f)
    ret2 = json.load(f)
    print(ret)

    上边的代码会报错,解决方法:

    dic1 = {'name':'oldboy1'}
    dic2 = {'name':'oldboy2'}
    dic3 = {'name':'oldboy3'}
    f = open('序列化',encoding='utf-8',mode='a')
    str1 = json.dumps(dic1)
    f.write(str1+'
    ')
    str2 = json.dumps(dic2)
    f.write(str2+'
    ')
    str3 = json.dumps(dic3)
    f.write(str3+'
    ')
    f.close()
    ​
    f = open('序列化',encoding='utf-8')
    for line in f:
        print(json.loads(line))
    

    1.2 pickle模块

    pickle模块是将Python所有的数据结构以及对象等转化成bytes类型,然后还可以反序列化还原回去。

    ​ 刚才也跟大家提到了pickle模块,pickle模块是只能Python语言识别的序列化模块。如果把序列化模块比喻成全世界公认的一种交流语言,也就是标准的话,json就是像是英语,全世界(python,java,php,C,等等)都遵循这个标准。而pickle就是中文,只有中国人(python)作为第一交流语言。

    ​ 既然只是Python语言使用,那么它支持Python所有的数据类型包括后面我们要讲的实例化对象等,它能将这些所有的数据结构序列化成特殊的bytes,然后还可以反序列化还原。使用上与json几乎差不多,也是两对四个方法。

    用于网络传输:dumps、loads

    用于文件写读:dump、load

    dumps、loads

    import pickle
    dic = {'k1':'v1','k2':'v2','k3':'v3'}
    str_dic = pickle.dumps(dic)
    print(str_dic)  # bytes类型
    

    dic2 = pickle.loads(str_dic)
    print(dic2) #字典

    # 还可以序列化对象
    import pickle
    def func():
        print(666)
    
    ret = pickle.dumps(func)
    print(ret,type(ret))  # b'x80x03c__main__
    func
    qx00.' <class 'bytes'>
    f1 = pickle.loads(ret)  # f1得到 func函数的内存地址
    f1()  # 执行func函数
    

    dump、load

    dic = {(1,2):'oldboy',1:True,'set':{1,2,3}}
    f = open('pick序列化',mode='wb')
    pickle.dump(dic,f)
    f.close()
    with open('pick序列化',mode='wb') as f1:
        pickle.dump(dic,f1)
    

    pickle序列化存储多个数据到一个文件中

    dic1 = {'name':'oldboy1'}
    dic2 = {'name':'oldboy2'}
    dic3 = {'name':'oldboy3'}
    ​
    f = open('pick多数据',mode='wb')
    pickle.dump(dic1,f)
    pickle.dump(dic2,f)
    pickle.dump(dic3,f)
    f.close()
    ​
    f = open('pick多数据',mode='rb')
    while True:
        try:
            print(pickle.load(f))
        except EOFError:
            break
    f.close()
    

    这时候机智的你又要说了,既然pickle如此强大,为什么还要学json呢?这里我们要说明一下,json是一种所有的语言都可以识别的数据结构。如果我们将一个字典或者序列化成了一个json存在文件里,那么java代码或者js代码也可以拿来用。但是如果我们用pickle进行序列化,其他语言就不能读懂这是什么了~所以,如果你序列化的内容是列表或者字典,我们非常推荐你使用json模块,但如果出于某种原因你不得不序列化其他的数据类型,而未来你还会用python对这个数据进行反序列化的话,那么就可以使用pickle。

    有志者,事竟成,破釜沉舟,百二秦关终属楚; 苦心人,天不负,卧薪尝胆,三千越甲可吞吴。 想到与得到中间还有两个字——做到。
  • 相关阅读:
    数据库
    数据库
    数据库
    数据库
    数据库
    数据库
    windows
    LeetCode : Word Pattern
    LeetCode : Perfect Number
    LeetCode : Minimum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/huoxc/p/12845853.html
Copyright © 2011-2022 走看看