Python 对象序列化

深藏阁楼爱情的钟 2022-09-13 14:26 179阅读 0赞

引言

将对象的状态信息转换为可以存储或传输的形式的过程叫作序列化

类似地从序列化后的数据转换成相对应的对象叫作 反序列化

本文介绍 Python 将对象序列化和反序化的两个模块

  • pickle
  • json

pickle

  1. # 序列化
  2. In [19]: num = 66
  3. In [20]: s = 'python'
  4. In [21]: pi = 3.14
  5. In [22]: li = [1, 2, 3]
  6. In [27]: b_num = pickle.dumps(num)
  7. In [28]: b_s = pickle.dumps(s)
  8. In [29]: b_pi = pickle.dumps(pi)
  9. In [30]: b_li = pickle.dumps(li)
  10. In [31]: b_num
  11. Out[31]: b'\x80\x03KB.'
  12. In [32]: b_s
  13. Out[32]: b'\x80\x03X\x06\x00\x00\x00pythonq\x00.'
  14. In [33]: b_pi
  15. Out[33]: b'\x80\x03G@\t\x1e\xb8Q\xeb\x85\x1f.'
  16. In [34]: b_li
  17. Out[34]: b'\x80\x03]q\x00(K\x01K\x02K\x03e.'
  18. In [35]: type(b_li)
  19. Out[35]: bytes
  20. # 反序列化
  21. In [47]: pickle.loads(b_num)
  22. Out[47]: 66
  23. In [48]: pickle.loads(b_s)
  24. Out[48]: 'python'
  25. In [49]: pickle.loads(b_pi)
  26. Out[49]: 3.14
  27. In [50]: li = pickle.loads(b_li)
  28. In [51]: li
  29. Out[51]: [1, 2, 3]
  30. In [52]: type(li)
  31. Out[52]: list

自定义的对象也能序列化

  1. class User:
  2. def __init__(self, name, sex):
  3. self.name = name
  4. self.sex = sex
  5. In [38]: user = User('hui', '男')
  6. In [39]: b_user = pickle.dumps(user)
  7. In [40]: b_user
  8. Out[40]: b'\x80\x03c__main__\nUser\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00huiq\x04X\x03\x00\x00\x00sexq\x05X\x03\x00\x00\x00\xe7\x94\xb7q\x06ub.'
  9. In [41]: type(b_user)
  10. Out[41]: bytes
  11. In [42]: user = pickle.loads(b_user)
  12. In [43]: type(user)
  13. Out[43]: __main__.User
  14. In [44]: user.name
  15. Out[44]: 'hui'
  16. In [45]: user.sex
  17. Out[45]: '男'

注意:pickle 序列化后数据都是字节(bytes)类型

pickle 也可以把对象序列化保存到文件,然后从文件反序化回对象。

  1. import pickle
  2. class User:
  3. def __init__(self, name, sex):
  4. self.name = name
  5. self.sex = sex
  6. user = User('ithui', '男')
  7. f = open('user.txt', mode='wb')
  8. pickle.dump(user, f)
  9. f.close()

从文件反序化回对象

  1. In [3]: f = open('user.txt', 'rb')
  2. ...: user = pickle.load(f)
  3. ...: f.close()
  4. ...:
  5. In [4]: user
  6. Out[4]: <__main__.User at 0x16c58ebef08>
  7. In [5]: user.name
  8. Out[5]: 'ithui'
  9. In [6]: user.sex
  10. Out[6]: '男'

pickle 模块虽然可以将对象序列化,但它只适用于 Python 语言,所以不方便数据交换。例如你将数据发给前端,js 则无法将数据转成自己想要的。

json

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如 json,因为 json 表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输进行数据交换。

json 字符串表示的对象就是 js 的对象,jsonPython 内置的数据类型对应如下:


































JSON类型 Python类型
{} dict
[] list
“string” ’str’ 或 u’unicode’
3.14 int 或 float
true / false True / False
null None
  1. In [7]: import json
  2. In [8]: info_dict = {
  3. ...: 'name': 'hui',
  4. ...: 'age': 22,
  5. ...: 'is_admin': True,
  6. ...: 'hobbies': ['下象棋', '写代码'],
  7. ...: 'other': None
  8. ...: }
  9. In [9]: info_json = json.dumps(info_dict)
  10. In [10]: info_json
  11. Out[10]: '{
  12. "name": "hui",
  13. "age": 22,
  14. "is_admin": true,
  15. "hobbies": ["\\u4e0b\\u8c61\\u68cb", "\\u5199\\u4ee3\\u7801"],
  16. "other": null
  17. }'
  18. # 对应的反序列化
  19. In [16]: info_d = json.loads(info_json)
  20. In [17]: info_d
  21. Out[17]:
  22. { 'name': 'hui',
  23. 'age': 22,
  24. 'is_admin': True,
  25. 'hobbies': ['下象棋', '写代码'],
  26. 'other': None}
  27. In [18]: type(info_d)
  28. Out[18]: dict

看看自定义的类对象能不能 json 序列化

  1. In [21]: import json
  2. In [22]: class User:
  3. ...:
  4. ...: def __init__(self, name, sex):
  5. ...: self.name = name
  6. ...: self.sex = sex
  7. ...:
  8. In [23]: user = User('ithui', '男')
  9. In [24]: json.dumps(user)
  10. TypeError: Object of type User is not JSON serializable

报错了,说 User 对象不能 json 序列化。有没有方法可以让自定义的对象可以转成 json,肯定是有的。

大致思路就是先把User对象转成可以被 json 序列化的对象,例如 dict 等,然后再把可序列化的对象给 json 模块。

  1. In [28]: def user2dict(obj):
  2. ...: return { 'name': obj.name, 'sex': obj.sex}
  3. ...:
  4. ...:
  5. In [29]: user = User('ithui', '男')
  6. In [30]: user_dict = user2dict(user)
  7. In [31]: user_dict
  8. Out[31]: { 'name': 'ithui', 'sex': '男'}
  9. In [32]: user_json = json.dumps(user_dict)
  10. In [33]: user_json
  11. Out[33]: '{"name": "ithui", "sex": "\\u7537"}'

也可以在序列化的时候指定一个转换器,可选参数 default 就是把任意一个对象变成一个可序列为JSON的对象,我们只需要为 User 专门写一个转换函数,再把函数传进去即可:

  1. In [28]: def user2dict(obj):
  2. ...: return { 'name': obj.name, 'sex': obj.sex}
  3. ...:
  4. ...:
  5. In [34]: user_json = json.dumps(user, default=user2dict)
  6. In [35]: user_json
  7. Out[35]: '{"name": "ithui", "sex": "\\u7537"}'

这样虽然可以把自定义的类对象转换成 json 但是要为不同的类专门定制不同的转换器,重复又麻烦,因此想到利用的每个类的 __dict__ 属性来序列化,它是一个 dict 对象,用来存储实例变量。也有少数例外,比如定义了 __slots__class

  1. In [36]: user.__dict__
  2. Out[36]: { 'name': 'ithui', 'sex': '男'}
  3. In [41]: json.dumps(user.__dict__)
  4. Out[41]: '{"name": "ithui", "sex": "\\u7537"}'

注意:如果是对象中的属性又嵌套另一个不能直接 json 序列化的对象,使用 __dict__ 属性照样无法正常序列化。

尾语

✍ 用 Code 谱写世界,让生活更有趣。❤️

✍ 万水千山总是情,点赞再走行不行。❤️

✍ 码字不易,还望各位大侠多多支持。❤️

发表评论

表情:
评论列表 (有 0 条评论,179人围观)

还没有评论,来说两句吧...

相关阅读

    相关 对象序列和反序列

    当程序运行的时候,对象在内存中是存在的,一旦程序结束,那么该对象便从内存中“消失”,如果想实现对象的“持久化存储”,即保存在硬盘中呢?那么就需要通过对象的序列化来实现了;同理,