Python -- 序列化

作者: 2023开始学 | 来源:发表于2019-05-19 17:06 被阅读0次

    pickle模块,json模块

    (1)把变量从内存中变成可存储或传输的过程,称之为序列化。Python中叫pickling,其他语言中也被称为serialization,marshalling,flattening等,都是相同的意思。

    (2)序列化之后,就可以把序列化后的内容(序列化后的内容是一个Bytes)写入磁盘,或者通过网络传输到别的机器上。

    (3)把变量内容从序列化的对象重新读到内存里,称之为反序列化,即unpickling。

    (4)Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用pickle保存那些不重要的数据,不能成功地反序列化也没关系。

    把一个对象序列化并写入文件,有两种方法:

    (1)pickle.dumps( )方法: 把任意对象序列化成一个bytes,然后,通过一定方式把这个bytes写入文件。
    import pickle
    
    d=dict(name='bob',age=23,score=98)
    print(pickle.dumps(d))
    
    (2)pickle.dump( )方法: 直接把对象序列化后写入一个file-like Object
    import pickle
    
    d=dict(name='shirley',age=23,score=98)
    f=open('dump.txt','wb')  #因为序列化之后是bytes,所以是wb
    pickle.dump(d,f)
    f.close()
    
    #通过pickle.dump()将对象保存到文件中,通过下面语句可以查看写入的序列化内容
    f=open("dump.txt",'rb')#rb
    print(f.read())
    

    pickle.dumps( )和pickle.dump( )的区别:就在于中间过程我们是否还需要再做一些操作。

    前者我们还要再做一些操作;后者不需要我们再进行任何操作。

    同序列化一样,当要把对象从磁盘读到内存时,有两种方法:

    (1)pickle.loads( ):可以先把内容读到一个bytes,然后用pickle.loads( )方法反序列化出对象
    (2)pickle.load( ):直接用pickle.load( )方法从一个file-like Object中直接反序列化出对象
    import pickle
    f=open('dump.txt','rb')
    s=pickle.load(f)
    f.close()
    print("反序列化后的对象s:",s)
    

    运行结果: 反序列化后的对象s: {'score': 98, 'age': 23, 'name': 'shirley'}

    注意:这个反序列化后的对象和原来的变量d是完全不相干的,它们只是内容相同而已。

    JSON

    Python内置的json模块可以实现从Python对象到JSON格式的转换

    (1)JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。

    (2)JSON是标准格式,比XML更快,而且可以直接在Web页面中读取。

    (3)JSON表示的对象就是标准的JavaScript语言的对象

    JSON和Python内置的数据类型对应如下:

    JSON类型------Python类型
    { }----------------dict
    [ ]----------------list
    "string"---------str
    1234.56--------int或float
    true/false-------True/False
    null---------------None

    注: 把Python对象转换成JSON格式时,只要是上面表格中列举的Python类型即可,其他类型,例如变量,就会报错。

    把Python对象转换成JSON格式:json.dumps( )方法,json.dump( )方法(可以直接把JSON写入一个file-like Object)
    要把JSON反序列化为Python对象:json.loads( )方法,json.load( )方法 (前者把JSON的字符串反序列化,后者从file-like Object 中读取字符串并反序列化)

    实例:把Python对象变成一个JSON

    import json
    d=dict(name='shirley',age=23,score=98)
    print(json.dumps(d))
    print(isinstance(json.dumps(d),str)) #判断序列化后的内容类型
    print(type(json.dumps(d)))#判断序列化后的内容类型
    

    运行结果:

    json.dumps(d): {"name": "shirley", "age": 23, "score": 98}
    True
    <class 'str'>

    JSON字符串反序列化:
    import json
    json_str = '{"age": 20, "score": 88, "name": "Bob"}'
    print(json.loads(json_str))
    print(type(json.loads(json_str)))
    

    注:由于JSON标准规定JSON编码是UTF-8,所以我们总是能正确地在Python的字符串str与JSON的字符串之间转换。

    JSON进阶

    由于Python的字典dict对象在上面表格列举的Python类型中,所以字典dict可以直接序列化为JSON的{ },不过,很多时候,更喜欢用class表示对象,比如定义Student类,然后序列化:

    import json
    
    class Student(object):
        def __init__(self,name,age,score):
            self.name=name
            self.age=age
            self.score=score
    
    
    s=Student('Nancy',24,89)
    print(json.dumps(s))
    

    运行结果:

    Traceback (most recent call last):

    ……………………………………

    TypeError: <main.Student object at 0x0000000000844208> is not JSON serializable

    错误的原因是:

    Student对象不是一个可序列化为JSON的对象。 如果class的实例对象都无法序列化为JSON,这肯定不合理。(我的理解是class的实例对象s是一个变量,不在上面列举的Python类型中,所以报错)

    前面的代码之所以无法把Student类实例序列化为JSON,是因为默认情况下,dumps( )方法不知道如何将Student实例变为一个JSON的{ }对象。

    解决办法是:定制JSON序列化

    ####对可选参数default进行设置,把任意class的实例变为dict
    
    print(json.dumps(s, default=lambda obj: obj.__dict__))
    

    通常类class的实例都有一个dict属性,它就是一个dict,用来存储实例变量(注意:是实例变量,即不同实例,该属性存储的变量不同,互不影响)。也有少数例外,比如定义了slots

    同理,把JSON反序列化为一个Student对象实例,loads( )方法首先转换出一个dict对象,然后,我们传入的object_hook函数负责把dict转换为Student实例

    class Student(object):
        def __init__(self,name,age,score):
            self.name=name
            self.age=age
            self.score=score
            
            
    import json
    
    def dict2student(d):
        return Student(d['name'], d['age'], d['score'])
    
    
    json_str = '{"age": 20, "score": 88, "name": "Bob"}'
    print(json.loads(json_str))
    print(json.loads(json_str, object_hook=dict2student))
    

    运行结果:

    {'age': 20, 'score': 88, 'name': 'Bob'}
    <main.Student object at 0x00000000007345C0>

    打印出的是反序列化的实例对象。

    小结

    Python语言特定的序列化模块是pickle,但如果要把序列化搞得更通用、更符合Web标准,就可以使用json模块。

    json模块的dumps( )和loads( )函数是定义得非常好的接口的典范。使用时只需要传入一个必须的参数。但是,当默认的序列化或反序列机制不满足我们的要求时,又可以传入更多的参数来定制序列化或反序列化的规则,既做到了接口简单易用,又做到了充分的扩展性和灵活性。

    参考网址:廖雪峰的官方网站

    相关文章

      网友评论

        本文标题:Python -- 序列化

        本文链接:https://www.haomeiwen.com/subject/mgeqzqtx.html