Python的序列化和反序列化

序列化(Serialzation)将对象的状态信息转换为可以存储或传输的形式的过程叫做序列化。反之将读取到的文本信息转换为对象叫做反序列化。本篇文章介绍三种Python下序列化的方法

Python Version: 3.5+

json

json是当今最流行的序列化格式之一,拥有超轻量级的数据交换格式。由于json的跨平台,跨语言交换信息的特性,在json中的字符串必须使用双引号引起来,在有的语言中有明确的定义,单引号只能表示单个字符,所以在json中使用单引号会产生意想不到的效果~~

json可以转化的Python对象有:

  • list
  • dict

本篇文章主要介绍json的4个方法:

  • dumps() 直接操作Python的数据类型转换成json字符串
  • loads() 直接将json字符串转换为Python的数据类型
  • dump() 先将Python的数据类型转换成json字符串,再写入文件
  • load() 先从文件中读取json字符串,再装换为Python的数据类型

dumps()

将list或dict对象序列化成json格式的字符串

1
2
3
4
5
6
7
8
9
10
11
import json

d = {'k1': 'v1'}
print(d, type(d))

result = json.dumps(d)
print(result, type(result))

------------
{'k1': 'v1'} <class 'dict'>
{"k1": "v1"} <class 'str'>

注意:上面已经强调了,在json中的字符串必须使用双引号。在上面的小例子中,我在创建Python字典的时候使用了单引号,但是在序列化成json格式时,json自动帮我们换上了双引号。

loads()

将json格式的字符串反序列化成list或dict对象

1
2
3
4
5
6
7
8
9
10
11
import json

s = '{"k1": "v1"}'
print(s, type(s))

d = json.loads(s)
print(d, type(d))

------------
{"k1": "v1"} <class 'str'>
{'k1': 'v1'} <class 'dict'>

dump()

将list或dict对象转换为json格式的字符串并写入到文件中

1
2
3
4
5
6
7
8
9
10
11
import json

d = {'k1': 'v1'}
print(d, type(d))

result = json.dump(d, open('a.json', 'w'))
print(result, type(result))

------------
{'k1': 'v1'} <class 'dict'>
None <class 'NoneType'>

使用dump写入文件后,不再有返回值

cat a.json

1
{"k1": "v1"}

load()

将文件中json格式的字符串转化为Python的list或dict对象

1
2
3
4
5
6
7
import json

d = json.load(open('a.json', 'r'))
print(d, type(d))

------------
{'k1': 'v1'} <class 'dict'>

pickle

pickle是Python语言自己的序列化方式,其优点是可以序列化任何Python对象,不仅限于json的list和dict。我们说Python是面向对象语言,万物皆对象,那么对于pickle来说就是Python的万物皆可序列化。这既是它的优点,也是它的缺点,由于pickle是Python自己的序列化方式,它不支持与其他语言的信息交换。json可以跨语言进行信息交换,但是pickle不行,pickle只能在Python语言下进行信息的交换,而且Python的版本不同,对pickle来说可能还会有兼容性的问题。

本篇文章主要介绍pickle的4个方法:

  • dumps()
  • loads()
  • dump()
  • load()

dumps()

将任何Python对象转化成二进制字节类型

1
2
3
4
5
6
7
8
9
10
11
import pickle

class User(object):
pass

u = User()
ret = pickle.dumps(u)
print(ret, type(ret))

------------
b'\x80\x03c__main__\nUser\nq\x00)\x81q\x01.' <class 'bytes'>

loads()

将二进制字节类型的数据转化为Python对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pickle

class User(object):
pass

u = User()
ret = pickle.dumps(u)
print(ret, type(ret))

o = pickle.loads(ret)
print(o, type(o))

------------
b'\x80\x03c__main__\nUser\nq\x00)\x81q\x01.' <class 'bytes'>
<__main__.User object at 0x101b78a90> <class '__main__.User'>

dump()

将Python对象转化成二进制字节,再写入到文件

1
2
3
4
5
6
7
8
import pickle

u = (1, 2, 3)
ret = pickle.dump(u, open('a.pkl', 'wb'))
print(ret, type(ret))

------------
None <class 'NoneType'>

注意:由于pickle把对象转化成了二进制的字节,所以在写入文件的时候,一定要加上b

load()

读取文件中的二进制字节,将其转化为Python对象

1
2
3
4
5
6
7
import pickle

o = pickle.load(open('a.pkl', 'rb'))
print(o, type(o))

------------
(1, 2, 3) <class 'tuple'>

注意:读取的时候也要加上b

YAML

YAML格式是最近几年大红大紫的交换格式,作为运维,最直观的感觉就是从运维自动化概念的开始,到容器技术的普及,让YAML的使用频率一高再高。YAML拥有比json更高的可读性,尤其用在配置文件(如saltstack,docker描述文件等)在合适不过了!

本篇文章主要介绍YAML的两个方法:

  • dump()
  • load()

由于YAML绝大部分的是对文件来操作,所以这里介绍时调换一下顺序,先介绍load()

首先写一个YAML的配置文件出来conf.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

host1:
IP: 192.168.1.1
app:
- httpd
- mysql
- php
memory: 16G

host2:
IP: 192.168.1.2
app:
- logstash
- kibana
- elasticsearch
- kafka
- zookeeper
memory: 128G

load()

1
2
3
4
5
6
7
import yaml

o = yaml.load(open('conf.yml'))
print(o, type(o))

------------
{'host1': {'app': ['httpd', 'mysql', 'php'], 'IP': '192.168.1.1', 'memory': '16G'}, 'host2': {'app': ['logstash', 'kibana', 'elasticsearch', 'kafka', 'zookeeper'], 'IP': '192.168.1.2', 'memory': '128G'}} <class 'dict'>

dump()

1
2
3
4
5
6
import yaml

o = yaml.load(open('conf.yml'))

o['host3'] = {'app': ['docker', 'jenkins'], 'IP': '192.168.1.3', 'memory': '64G'}
yaml.dump(o, open('conf.yml', 'w'))
1
2
3
4
5
6
7
8
9
10
11
12
host1:
IP: 192.168.1.1
app: [httpd, mysql, php]
memory: 16G
host2:
IP: 192.168.1.2
app: [logstash, kibana, elasticsearch, kafka, zookeeper]
memory: 128G
host3:
IP: 192.168.1.3
app: [docker, jenkins]
memory: 64G

可以使用default_flow_style=False来保证高可读性

1
2
3
4
5
6
7
import yaml

o = yaml.load(open('conf.yml'))

o['host3'] = {'app': ['docker', 'jenkins'], 'IP': '192.168.1.3', 'memory': '64G'}
#yaml.dump(o, open('conf.yml', 'w'))
yaml.dump(o, open('conf.yml', 'w'), default_flow_style=False)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
host1:
IP: 192.168.1.1
app:
- httpd
- mysql
- php
memory: 16G
host2:
IP: 192.168.1.2
app:
- logstash
- kibana
- elasticsearch
- kafka
- zookeeper
memory: 128G
host3:
IP: 192.168.1.3
app:
- docker
- jenkins
memory: 64G