纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

Python序列化与反序列 Python序列化与反序列化相关知识总结

AI悦创   2021-06-08 我要评论
想了解Python序列化与反序列化相关知识总结的相关内容吗AI悦创在本文为您仔细讲解Python序列化与反序列的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Python序列化,python反序列下面大家一起来学习吧

Python序列化与反序列

在程序运行的过程中所有的变量都是在内存中比如定义一个 dict:

d = dict(name='Bob', age=20, score=88)

可以随时修改变量比如把 name 改成 ‘Bill'但是一旦程序结束变量所占用的内存就被操作系统全部回收如果没有把修改后的 ‘Bill' 存储到磁盘上下次重新运行程序变量又被初始化为 ‘Bob'

我们把变量从内存中变成可存储或传输的过程称之为序列化在 Python 中叫 pickling在其他语言中也被称之为 serializationmarshallingflattening 等等都是一个意思
序列化之后就可以把序列化后的内容写入磁盘或者通过网络传输到别的机器上

未命名表单.png

反过来把变量内容从序列化的对象重新读到内存里称之为反序列化即 unpickling

Python 提供了 pickle 模块来实现序列化首先我们尝试把一个对象序列化并写入文件:

In [1]: import pickle

In [2]: d = dict(name='Bob', age=20, score=88)

In [3]: pickle.dumps(d)
Out[3]: b'\x80\x04\x95$\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x03Bob\x94\x8c\x03age\x94K\x14\x8c\x05score\x94KXu.'

pickle.dumps() 方法把任意对象序列化成一个 bytes然后就可以把这个 bytes 写入文件或者用另一个方法 pickle.dump() 直接把对象序列化后写入一个 file-like Object:

In [5]: f = open('dump.txt', 'wb')

In [6]: d = dict(name='Bob', age=20, score=88)

In [7]: pickle.dump(d, f)

In [8]: f.close()

看看写入的 dump.txt 文件一堆乱七八糟的内容这些都是 Python 保存的对象内部信息

image.png

当我们要把对象从磁盘读到内存时可以先把内容读到一个 bytes然后用 pickle.loads() 方法反序列化出对象也可以直接用 pickle.load() 方法从一个 file-like Object 中直接反序列化出对象我们打开另一个 Python 命令行来反序列化刚才保存的对象:

In [23]: f = open('dump.txt', 'rb')

In [24]: d = pickle.load(f)

In [25]: f.close()

In [26]: d
Out[26]: {'name': 'Bob', 'age': 20, 'score': 88}

变量的内容又回来了!

当然这个变量和原来的变量是完全不相干的对象它们只是内容相同而已

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

JSON

如果我们要在不同的编程语言之间传递对象就必须把对象序列化为标准格式比如 XML但更好的方法是序列化为 JSON因为 JSON 表示出来就是一个字符串可以被所有语言读取也可以方便地存储到磁盘或者通过网络传输JSON 不仅是标准格式并且比 XML 更快而且可以直接在 Web 页面中读取非常方便

JSON 表示的对象就是标准的 JavaScript 语言的对象JSON 和 Python 内置的数据类型对应如下:

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

Python 内置的 json 模块提供了非常完善的 Python 对象到 JSON 格式的转换我们先看看如何把 Python对象变成一个 JSON:

In [27]: import json

In [28]: d = dict(name='Bob', age=20, score=88)

In [29]: json.dumps(d)
Out[29]: '{"name": "Bob", "age": 20, "score": 88}'

In [30]: type(json.dumps(d))
Out[30]: str

dumps() 方法返回一个 str内容就是标准的 JSON类似的dump() 方法可以直接把 JSON 写入一个 file-like Object

要把 JSON 反序列化为 Python 对象用 loads() 或者对应的 load() 方法前者把 JSON 的字符串反序列化后者从 file-like Object 中读取字符串并反序列化:

In [31]: json_str = '{"age": 20, "score": 88, "name": "Bob"}'

In [32]: json.loads(json_str)
Out[32]: {'age': 20, 'score': 88, 'name': 'Bob'}

In [33]: type(json.loads(json_str))
Out[33]: dict

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

JSON 进阶

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('Bob', 20, 88)
print(json.dumps(s))

运行代码毫不留情地得到一个 TypeError:

Traceback (most recent call last):
  ...
TypeError: Object of type Student is not JSON serializable

错误的原因是 Student 对象不是一个可序列化为 JSON 的对象

如果连 class 的实例对象都无法序列化为 JSON这肯定不合理!

别急我们仔细看看 dumps() 方法的参数列表可以发现除了第一个必须的 obj 参数外dumps() 方法还提供了一大堆的可选参数:https://docs.python.org/3/library/json.html#json.dumps

这些可选参数就是让我们来定制 JSON 序列化前面的代码之所以无法把 Student 类实例序列化为 JSON是因为默认情况下dumps() 方法不知道如何将 Student 实例变为一个 JSON 的 {} 对象

可选参数 default 就是把任意一个对象变成一个可序列为 JSON 的对象我们只需要为 Student 专门写一个转换函数再把函数传进去即可:

In [40]: s.name
Out[40]: 'Bob'

In [41]: s.age
Out[41]: 20

In [42]: s.score
Out[42]: 88
def student2dict(std):
    return {
        'name': std.name,
        'age': std.age,
        'score': std.score
    }

这样Student 实例首先被 student2dict() 函数转换成 dict然后再被顺利序列化为 JSON:

print(json.dumps(s, default=student2dict))

不过下次如果遇到一个 Teacher 类的实例照样无法序列化为 JSON再写一个函数 也可以但是我们可以偷个懒把任意 class 的实例变为 dict:

print(json.dumps(s, default=lambda obj: obj.__dict__))

因为通常 class 的实例都有一个 __dict__ 属性它就是一个 dict用来存储实例变量也有少数例外比如定义了 __slots__ 的 class

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

def dict2student(d):
    return Student(d['name'], d['age'], d['score'])

运行结果如下:

In [48]: json_str = '{"age": 20, "score": 88, "name": "Bob"}'

In [49]: def dict2student(d):
    ...:     return Student(d['name'], d['age'], d['score'])
    ...:

In [50]: print(json.loads(json_str, object_hook=dict2student))
<__main__.Student object at 0x1065c6f70>

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

练习

对中文进行 JSON 序列化时json.dumps() 提供了一个 ensure_ascii 参数观察该参数对结果的影响:

import json

obj = dict(name='小明', age=20)
s = json.dumps(obj, ensure_ascii=True)
print(s)

小结

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

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


相关文章

猜您喜欢

  • Python Anaconda环境变量 Python激活Anaconda环境变量的详细步骤

    想了解Python激活Anaconda环境变量的详细步骤的相关内容吗黄佳俊、在本文为您仔细讲解Python Anaconda环境变量的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Python,,Anaconda环境变量,Python,,Anaconda变量下面大家一起来学习吧..
  • MyBatis快速入门 MyBatis入门学习教程-MyBatis快速入门

    想了解MyBatis入门学习教程-MyBatis快速入门的相关内容吗代码学习在本文为您仔细讲解MyBatis快速入门的相关知识和一些Code实例欢迎阅读和指正我们先划重点:java快速入门,MyBatis新手教程下面大家一起来学习吧..

网友评论

Copyright 2020 www.fresh-weather.com 【世纪下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式