Tips 24

序列化对象

pickle

序列化的概念很简单,内存里面的数据,想保存下来。下次使用时,又能容易恢复,而且不想使用大型的数据库。这种情况下,pickle模块是理想的,它是python标准库的一部分,所以总是可用的。它的大部分和python解释器本身一样是用C编写的,可用存储任意复杂的python数据结构。

  • python支持的原生类型:布尔,整数,浮点数,复数,字符串,字符数组,None
  • 列表,元组,字典和集合
  • 列表,元组,字典和集合嵌套列表,元组,字典和集合(直到python支持最大的递归层数)
  • 函数,类,和类的实例

保存数据到文件

>>> entry
{'article_link': 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition', 'published': True, 'published_date': time.struct_time(tm_year=2009, tm_mon=3, tm_mday=27, tm_hour=22, tm_min=20, tm_sec=42, tm_wday=4, tm_yday=86, tm_isdst=-1), 'internal_id': b'\xde\xd5\xb4\xf8', 'tags': ('diveintopython', 'docbook', 'html'), 'comments_link': None, 'title': 'Dive into history, 2009 edition'}

定义了一个包含多个数据格式的字典

保存数据

>>> import pickle
>>> with open('entry.pickle', 'wb') as f: # open打开一个文件,文件模式'wb'
...     pickle.dump(entry, f)  # pickle模块的dump()函数接收一个可序列化的python数据结构。使用pickle协议将其序列化为二进制,保存到entry.pickle

pickle协议是python特定的。该协议也在修改变化,最新的协议是二进制格式的,所以使用时注意其版本变化

读取数据

>>> with open('entry.pickle', 'rb') as f: # with语句,二进制模式打开entry.pickle文件
...     entrya = pickle.load(f)   # pickle.load()函数接收一个流对象,从文件读取序列化后的数据,创建一个新的python对象
... 
>>> entrya # 和前面的entry内容一样
{'published_date': time.struct_time(tm_year=2009, tm_mon=3, tm_mday=27, tm_hour=22, tm_min=20, tm_sec=42, tm_wday=4, tm_yday=86, tm_isdst=-1), 'comments_link': None, 'title': 'Dive into history, 2009 edition', 'article_link': 'http://diveintomark.org/archives/2009/03/27/dive-into-history-2009-edition', 'internal_id': b'\xde\xd5\xb4\xf8', 'published': True, 'tags': ('diveintopython', 'docbook', 'html')}

pickle.dump()/pickle.load()循环的结果是一个和原始数据结构等同的新的数据结构

>>> with open('entry.pickle', 'rb') as f:
...     entryb = pickle.load(f)
... 
>>> entryb == entry # 另外读取的entryb和之前的entry相等
True 
>>> entryb is entry # 虽然相等,但不是一个
False

保存到内存

>>> b = pickle.dumps(entry) # 这里是dumps
>>> type(b)   # 保存的是二进制数据格式
<class 'bytes'>
>>> entry3 = pickle.loads(b) # 接收包含序列化后的数据bytes对象
>>> entry3 == entry
True

pickle文件调试

>>> import pickletools
>>> with open('entry.pickle', 'rb') as f:
...     pickletools.dis(f)
... 
    0: \x80 PROTO      3
...
highest protocol among opcodes = 3  # 显示了pickle协议的版本号

JSON

pickle序列化数据是python特定的,但json是可以跨语言使用的。

json是基于文本的,不是二进制。json值是大小写敏感的。由于是文本格式的,存在空白的问题。json允许在值之间有任意数目的空白(空格,跳格,回车,换行)。空白是无关紧要的,可以根据需要添加任意的空白。python的josn模块在编码时支持pretty-printing选项 json同样要注意编码格式

保存数据

json看起来想在javascript手工定义的数据结构。支持js中eval()函数来解码json序列化的数据。

>>> basic_entry
{'tags': ('diveintopython', 'docbook', 'html'), 'id': 256, 'comments_link': None, 'published': True, 'title': 'Dive into history, 2009 edition'}
>>> import json
>>> with open('basic.json', mode='w', encoding='utf-8') as f: # json是文本格式,所以w打开即可
...     json.dump(basic_entry, f) # 同pickle一样,json定义了dump()函数,接收一个流对象和一个可写的流对象。然后写入
...

json是文本格式,所以可是用cat查看一下其内容

>>> with open('basic-pretty.json', mode='w', encoding='utf-8') as f:
...     json.dump(basic_entry, f, indent=2) # indent参数指定空格数量进行缩进嵌套保存数据

读取数据

类似pickle模块,json模块有一个load()函数接受一个流对象,从中读取JSON编码过的数据,并且创建该JSON数据结构的python对象的镜像

>>> with open('basic.json', 'r', encoding='utf-8') as f:
...     entry = json.load(f)
... 
>>> entry
{'tags': ['diveintopython', 'docbook', 'html'], 'id': 256, 'comments_link': None, 'published': True, 'title': 'Dive into history, 2009 edition'}

Python中还有其他一些序列化对象的如dbm、shelve等等

by 李鹏