pickle是一个Python的内置模块,用于在Python中实现对象结构序列化和反序列化。Python序列化是一个将Python对象层次结构转换为可以本地存储或者网络传输的字节流的过程,反序列化则是将字节流还原为将Python对象层次结构。

数据序列化的功能简单理解为把不能直接存储的数据存储到磁盘中,从而延长对象的生命周期。Python的常用序列化库有两个,即json和pickle。json库和pickle库的主要区别有两点:

  • pickle可以序列化Python中所有的数据类型,包括类,函数,一般存储为二进制文件。而json只能序列化Python基本的数据类型,转储结果非常容易阅读。
  • pickle只能在Python中使用,而json是能够在不同语言之间交换数据的。

pickle一般情况下比json慢,尤其是数据量很大的情况下。pickle和json都有四种基础方法:

方法 作用
dump 序列化写入文件
load 读取文件反序列化
dumps 序列化返回对象
loads 反序列化对象

1 pickle使用

pickle.dump()函数用于将python结构序列化,并存为二进制文件。 pickle.dump函数接受三个参数,其中第一个参数包含要存储在文件中的对象,第二个参数给出以二进制模式写入所需文件时获得的文件对象。第三个参数表示序列化协议。

对于pickle的协议选取,目前有5种不同的协议可用(出自Python object serialization)。使用的协议越高,读取生成的pickle所需的Python版本越新。这些协议包括:

  • 协议版本0是原始的“人类可读”协议,与Python的早期版本向后兼容。
  • 协议版本1是一种旧的二进制格式,也与Python的早期版本兼容。
  • 协议版本2于Python2.3引入,提供了更为有效的序列化方式。
  • 协议版本3于Python3.0引入。它明确支持bytes对象,这也是Python的默认协议,也是需要与其他Python3版本兼容时的推荐协议。
  • 协议版本4于Python3.4引入。它增加了对超大对象的支持,对更多类型的对象进行序列化,并对一些数据格式优化。

通过0到4可以设置不同的协议,该协议参数默认为None,None表示使用Python版本使用的默认协议。选择-1表示最高协议。此外可以通过常量设置该协议,分别是:

  • pickle.HIGHEST_PROTOCOL:表示最高协议。
  • pickle.DEFAULT_PROTOCOL:表示默认协议。
import pickle
print("当前python环境最高序列化协议版本为:{}".format(pickle.HIGHEST_PROTOCOL))
print("当前python环境默认序列化协议版本为:{}".format(pickle.DEFAULT_PROTOCOL))
当前python环境最高序列化协议版本为:4
当前python环境默认序列化协议版本为:3
# 序列化实例
import pickle
import numpy as np data = {
"name": "data struct",
"number": 123.456,
"tuple": ("first", False, 10.01),
"numpy_data": np.ones((9,9),np.uint8)
}
# 保存到本地,这个文件名包含后缀可以随意命名,反正是二进制文件
with open('data.bin', 'wb') as f:
# 设置最底层协议
pickle.dump(data, f, 0) # 查看文件大小
!du -h data.bin
print('---分界线---')
# 查看文件前十行,发现有可读文字
!cat data.bin | head -n 5
4.0K	data.bin
---分界线---
(dp0
Vname
p1
Vdata struct
p2
# 保存到本地,这个文件名包含后缀可以随意命名,反正是二进制文件
with open('data.bin', 'wb') as f:
# 设置最底层协议
pickle.dump(data, f, 1) # 查看文件大小
!du -h data.bin
print('---分界线---')
# 查看文件前2行
!cat data.bin | head -n 2
4.0K	data.bin
---分界线---
}q (X nameqX data structqX numberqG@^�/��wX tupleq(X firstqI00
G@$�Q�tqX
# 保存到本地,这个文件名包含后缀可以随意命名,反正是二进制文件
with open('data.bin', 'wb') as f:
# 设置默认协议
pickle.dump(data, f, pickle.DEFAULT_PROTOCOL) # 查看文件大小
!du -h data.bin
print('---分界线---')
# 查看文件前2行
!cat data.bin | head -n 2
4.0K	data.bin
---分界线---
�}q (X nameqX data structqX numberqG@^�/��wX tupleqX firstq�G@$�Q녇qX
numpy_dataqcnumpy.core.multiarray
# 保存到本地,这个文件名包含后缀可以随意命名,反正是二进制文件
with open('data.bin', 'wb') as f:
# 设置默认协议
pickle.dump(data, f, 4) # 查看文件大小
!du -h data.bin
print('---分界线---')
# 查看文件前2行
!cat data.bin | head -n 2
4.0K	data.bin
---分界线---
��/ }�(�name��data struct��number�G@^�/��w�tuple��first��G@$�Q녇��
numpy_data��numpy.core.multiarray��_reconstruct����numpy��ndarray���K ��Cb���R�(KK K ��h�dtype����u1�����R�(K�|�NNNJ����J����K t�b�CQ�t�bu.

如果想反序列化,重新读入文件,直接用pickle.load函数就行了。序列化协议是自动检测的,不需要指定。此外还有两个参数encoding和errors告诉pickle如何反序列低于当前python版本的序列化文件,默认值就行了。

import pickle

with open('data.bin', 'rb') as f:
data = pickle.load(f)
print(type(data))
print(data['name'])
print(data.keys())
<class 'dict'>
data struct
dict_keys(['name', 'number', 'tuple', 'numpy_data'])

通过dumps函数将对象的序列化表示作为bytes对象返回,而不是将其写入文件。通过loads函数则将bytes对象反序列化。注意bytes是 Python3新增的类型,bytes只负责以二进制形式来存储数据。

data = [1,2,3]

# 序列化,返回bytes对象
dumped = pickle.dumps(data)
print(dumped)
print(type(dumped))
print(len(dumped)) # 反序列化
loaded = pickle.loads(dumped)
print(loaded)
b'\x80\x03]q\x00(K\x01K\x02K\x03e.'
<class 'bytes'>
14
[1, 2, 3]

序列化和反序列化的过程可以通过__getstate__ 和__setstate__函数来影响。其中__getstate__函数在序列化时调用,__setstate__函数在反序列化时调用。

一个实例如下,在序列化时指定序列化某些参数,反序列化时恢复参数。

import pickle

class MyData:

    def __init__(self, x):

        self.x = x
self.y = self.sqrt(x) def sqrt(self,x):
return x**x def __getstate__(self):
self.state = "ok"
print("enter getstate")
# self.__dict__存储关于self.xxx的一些东西
odict = self.__dict__.copy()
del odict['y']
print(odict)
return odict def __setstate__(self, input):
print("enter setstate")
print(input)
self.x = input['x']
self.y = self.sqrt(self.x) obj = MyData(3)
# 序列化
print("序列化")
dumped = pickle.dumps(obj)
# 反序列化
print("反序列化")
loaded = pickle.loads(dumped)
print("反序列化结果", loaded.y)
序列化
enter getstate
{'x': 3, 'state': 'ok'}
反序列化
enter setstate
{'x': 3, 'state': 'ok'}
反序列化结果 27

2 pickle加速

当要序列化的对象特别大时,pickle加载和保存序列化对象会成为代码的性能瓶颈。一般有三种办法加速pickle序列化过程。主要有:

  • 使用更高的协议版本
  • 使用cPickle代替pickle
  • 禁用垃圾收集器

下面几个例子会给出使用方法,不过加速效果不明显,因为数据量不大,写个代码mark下。

直接使用pickle

import time
import pickle
import numpy as np
import os
def time_count(func):
def inner(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
end = time.time()
print('{}用时:{}秒'.format(func.__name__,end-start))
return inner @time_count
def pickle_dump(data,filepath):
with open(filepath, 'wb') as f:
pickle.dump(data, f) @time_count
def pickle_load(filepath):
with open(filepath, 'rb') as f:
data = pickle.load(f)
return data data = np.ones((10000, 10000))
filepath = "file.dat"
pickle_dump(data,filepath)
pickle_load(filepath)
os.remove(filepath)
time.sleep(2)
pickle_dump用时:1.7647628784179688秒
pickle_load用时:1.7913622856140137秒

使用pickle最高协议

将参数协议指定为-1,即可,但是加速可能效果不明显。具体看数据。

import time
import pickle
import numpy as np
import os def time_count(func):
def inner(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
end = time.time()
print('{}用时:{}秒'.format(func.__name__,end-start))
return inner @time_count
def pickle_dump(data,filepath):
with open(filepath, 'wb') as f:
# 使用最高版本协议
pickle.dump(data, f, -1) @time_count
def pickle_load(filepath):
with open(filepath, 'rb') as f:
data = pickle.load(f)
return data data = np.ones((10000, 10000))
filepath = "file.dat"
pickle_dump(data,filepath)
pickle_load(filepath)
os.remove(filepath)
time.sleep(2)
pickle_dump用时:1.731525182723999秒
pickle_load用时:1.7664134502410889秒

用cPickle代替pickle

最简单方式是使用cPickle而不是pickle。cPickle与pickle是完全相同的模块,具有相同的功能、相同的参数。唯一区别是cPickle用C语言编写的,这使cPickle速度更快。

import time
# python3 导入cPickle方式
import _pickle as cPickle
import numpy as np
import os def time_count(func):
def inner(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
end = time.time()
print('{}用时:{}秒'.format(func.__name__,end-start))
return inner @time_count
def pickle_dump(data,filepath):
with open(filepath, 'wb') as f:
# 使用最高版本协议
cPickle.dump(data, f, -1) @time_count
def pickle_load(filepath):
with open(filepath, 'rb') as f:
data = cPickle.load(f)
return data data = np.ones((10000, 10000))
filepath = "file.dat"
pickle_dump(data,filepath)
pickle_load(filepath)
os.remove(filepath)
time.sleep(2)
pickle_dump用时:1.7443737983703613秒
pickle_load用时:1.7894999980926514秒

禁用垃圾回收

垃圾收集器会减慢处理速度,禁用它可以提高性能。

import time
import pickle
import numpy as np
import os
import gc # 禁用垃圾回收
gc.disable() def time_count(func):
def inner(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
end = time.time()
print('{}用时:{}秒'.format(func.__name__,end-start))
return inner @time_count
def pickle_dump(data,filepath):
with open(filepath, 'wb') as f:
# 使用最高版本协议
pickle.dump(data, f, -1) @time_count
def pickle_load(filepath):
with open(filepath, 'rb') as f:
data = pickle.load(f)
return data data = np.ones((10000, 10000))
filepath = "file.dat"
pickle_dump(data,filepath)
pickle_load(filepath)
os.remove(filepath)
time.sleep(2) # 开启垃圾回收
gc.enable()
pickle_dump用时:1.8271889686584473秒
pickle_load用时:1.7800366878509521秒

3 参考

[python] ​Python数据序列化模块pickle使用笔记的更多相关文章

  1. Python 基础之序列化模块pickle与json

    一:pickle 序列化模块把不能够直接存储的数据,变得可存储就是序列化把存储好的数据,转化成原本的数据类型,加做反序列化 php: 序列化和反序列化(1)serialize(2)unserializ ...

  2. 【转】Python之数据序列化(json、pickle、shelve)

    [转]Python之数据序列化(json.pickle.shelve) 本节内容 前言 json模块 pickle模块 shelve模块 总结 一.前言 1. 现实需求 每种编程语言都有各自的数据类型 ...

  3. Python之数据序列化(json、pickle、shelve)

    本节内容 前言 json模块 pickle模块 shelve模块 总结 一.前言 1. 现实需求 每种编程语言都有各自的数据类型,其中面向对象的编程语言还允许开发者自定义数据类型(如:自定义类),Py ...

  4. Python序列化模块pickle和json使用和区别

    这是用于序列化的两个模块: • json: 用于字符串和python数据类型间进行转换 • pickle: 用于python特有的类型和python的数据类型间进行转换 Json模块提供了四个功能:d ...

  5. Python中的序列化以及pickle和json模块介绍

    Python中的序列化指的是在程序运行期间,变量都是在内存中保存着的,如果我们想保留一些运行中的变量值,就可以使用序列化操作把变量内容从内存保存到磁盘中,在Python中这个操作叫pickling,等 ...

  6. json&pickle数据序列化模块

    用于序列化的模块 json,通用的序列化方式,序列化成为str类型,支持所有语言识别,序列化的数据具有局限性. pickle,python的所有数据类型都可以被序列化,序列化为bites格式,只适用于 ...

  7. Python进阶(九)----json模块, pickle模块, os模块,sys模块,hashlib模块

    Python进阶----json模块, pickle模块, os模块,sys模块,hashlib模块 一丶序列化模块 什么是序列化: ​ 将一种数据结构,转换成一个特殊的序列(特殊字符串,用于网络传输 ...

  8. Python内置模块之序列化模块

    序列化模块 json dumps loads dump load pickle dumps loads dump load shelve json 1: dumps/loads import json ...

  9. python存取数据进阶技巧-pickle,array模块

    我们在存/取数据时,没有必要存成文本形式,多试试二进制形式,文本只是骗骗眼睛的,要更快和更高效 1.数组形式 如果我们需要一个之包含数字的列表,那就试试array.array,注意,不是numpy模块 ...

随机推荐

  1. 【C++】从零开始的CS:GO逆向分析3——写出一个透视

    [C++]从零开始的CS:GO逆向分析3--写出一个透视 本篇内容包括: 1. 透视实现的方法介绍 2. 通过进程名获取进程id和进程句柄 3. 通过进程id获取进程中的模块信息(模块大小,模块地址, ...

  2. 基于雪花算法的增强版ID生成器

    sequence 基于雪花算法的增强版ID生成器 解决了时间回拨的问题 无需手动指定workId, 微服务环境自适应 可配置化 快速开始 依赖引入 <dependency> <gro ...

  3. javascript编程单线程之同步模式

    javascript编程单线程之同步模式 主流的js 环境都是单线程吗模式执行js 代码, js采用为单线程的原因与最开始设计初衷有关,最早是运行在浏览器端的脚本语言,目的是为了实现页面上的动态交互, ...

  4. nrf9160做主控连接阿里云——(mqtt_simple例程)

    简介:基本每一个云都支持MQTT,这种轻量级协议在数据量不大的应用上是一个很好的选择.上一篇博客使用SLM例程去连接了阿里云,本次使用mqtt_simple去连接云进行测试,关于一些已近在前面文章中演 ...

  5. OpenFOAM 编程 | 求解捕食者与被捕食者模型(predator-prey model)问题(ODEs)

    0. 写在前面 本文问题参考自文献 \(^{[1]}\) 第一章例 6,并假设了一些条件,基于 OpenFOAM-v2206 编写程序数值上求解该问题.笔者之前也写过基于 OpenFOAM 求解偏分方 ...

  6. docker支持ipv6

    方法 方法一.Pv6地址 不为容器中的服务特别分配IPv6地址. 只要Docker把外部的IPv6地址端口映射到容器的IPv4端口上,随后访问主机的IPv6相应端口即可. 方法二.为Docker网络分 ...

  7. 发布 .NET 7 MAUI / MAUI Blazor 应用到 Windows 应用商店

    .NET MAUI 目前仅允许发布 MSIX 包. 创建签名证书发布到本地传送门 [https://www.cnblogs.com/densen2014/p/16567384.html] 使用 Vis ...

  8. 强软弱引用,ThreadLocal和内存泄漏

    强引用 写法:Object obj=new Object() 引用强度:最强 只要被引用着,就不会被gc(垃圾回收)回收掉. 软引用 写法:SoftReference<String> sr ...

  9. 12 张图看懂 CPU 缓存一致性与 MESI 协议,真的一致吗?

    本文已收录到  GitHub · AndroidFamily,有 Android 进阶知识体系,欢迎 Star.技术和职场问题,请关注公众号 [彭旭锐] 进 Android 面试交流群. 前言 大家好 ...

  10. 【2022-11-28】Docker部署搭建Gitlab

    一.环境准备 1. 准备一台虚拟机\或者购买服务器 2. 虚拟机硬件要求 2.1 内存不得少于4G,否则启动会报502错误,可自行百度解决,将虚拟机的swap分区调整为2G大小即可 2.2 CPU2核 ...