js 对象序列化,python 对象序列化
我们想把最近爬虫得到的下载结果存档。这个结果是计算机编程语言对象。我不打算简单地保存超文本标记语言或json,而是想让整个下载过程都能恢复。因此,我们考虑使用计算机编程语言内置的泡菜库(腌菜黄瓜库),将序列化对象定为字节,可以根据需要进行反序列化。
通过以下代码可以轻松了解泡菜的使用方法和功能。
一
2
3
四
5
6
七
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
在[2]中:导入泡菜
在[3]答中:类:通过。
在[4]中:a=A(
In[5]:a.foo=hello
在[6]中:a.bar=2
in [7] : pick _ ed=pickle.dumps(一个(
在[8]:挑选
out[8]:b \ X80 \ x03c _ main _ _ na _ NQ _ x00()x81q \ x01)q x02(x x03)x00)))
in[9]:un pick=pickle。loads(pick _ ed))))))。
在[10]:取消拾取
out [ 10 ] : _ _ main _.aat0x 10a e 67278
在[11]中
out [ 11 ] : _ _ main _.aat0x 10a e 67128
in[12]:dir(unpick))。
Out[12]:
[__class__ ,
__delattr__ ,
__dict__ ,
__dir__ ,
__doc__ ,
__eq__ ,
__format__ ,
__ge__ ,
__getattribute__ ,
__gt__ ,
__hash__ ,
__init__ ,
__init_subclass__ ,
__le__ ,
__lt__ ,
__模块_ _ ,
__ne__ ,
__new__ ,
__reduce__ ,
__reduce_ex__ ,
__repr__ ,
__setattr__ ,
__sizeof__ ,
__slotnames__ ,
__str__ ,
__subclasshook__ ,
__weakref__ ,
酒吧,
foo]
In[13]:unpick.foo
Out[13]:”你好"
In[14]:unpick.bar
Out[14]:2
您会发现泡菜的用法与数据有点相似,但有几个根本的区别:
数据是语言间通用的数据交换形式,一般用文本表示,可供人类阅读泡菜。用于序列化计算机编程语言对象。但是,对于Python,序列化的结果是二进制数据,人类无法读取。然后,json缺省情况下只能序列化某些内置类型,而泡菜可以序列化相当多的数据。
另一个旧整理也内置其中。但是,这个库主要针对。力兴文件。不支持自定义类型,并且不完整。例如,如果无法处理循环APP,并且有引用自己的对象,则使用整理时计算机编程语言解释器会挂起。
版本兼容问题
由于泡菜是针对计算机编程语言的,Python有不同的版本(并且2与3之间差异非常大),所以就要考虑到序列化出来的对象能不能被更高(或低?)版本的计算机编程语言反序列化出来。
目前一共有5个泡菜的协议版本,版本越高对应皮顿的版本越高,0-2针对蟒蛇皮2,3-4针对Python3 .
协议版本0是原始的"人类可读"协议,并向后兼容早期版本的Python .
协议版本一是一种旧的二进制格式,也与计算机编程语言的早期版本兼容。
Python 2.3中引入了协议版本2。它提供了更有效的新型类的酸洗。有关协议2带来的改进的信息,请参考EP 307 .(从这个版本往后,性能有显著提高)
Python 3.0中添加了协议版本3。它显式支持对于目标来说,并且不能被Python 2.x取消拾取。这是默认协议,并且在需要与其他Python 3版本兼容时是推荐的协议。
Python 3.4中添加了协议版本4。它增加了对非常大的对象的支持,支持更多种类的对象,以及一些数据格式优化。有关协议四带来的改进的信息,请参考欧洲专利3154号.
泡菜的大多数入口函数(例如dump(),转储(),选取器构造器)都接受一个协议版本的参数,其中内置了两个变量:
泡菜。最高_协议目前是四
泡菜。默认_协议目前是3
用法
类似于内置的json模块接口,dump()用于返回序列化结果,dump()用于序列化然后写入文件。类似的还有loads()和loads()。其中,可以在序列化转储时指定协议的版本,但不能在反序列化时指定,版本将被自动识别。这非常类似于zip命令。
内置类型的序列化
大多数内置类型支持序列化和反序列化。要特别注意功能。一个函数的序列化只需要它的名字和它所在的模块。函数的代码和属性(Python的函数是一级对象,可以有属性)不会序列化。这就要求函数所在的模块在unpickle环境下必须是可导入的,否则就会出现ImportError或AttributeError。
这里有个有趣的事情:所有的lambda函数都不是Pickle。因为他们的名字叫。
自定义类型的序列化
就像本文开头的实验代码一样,在大多数情况下,我们不需要额外的操作就可以实现自定义对象的序列化/反序列化。需要注意的是,在反序列化的过程中,并不是调用class的__init__()来初始化一个对象,而是创建一个新的未初始化的实例,然后恢复其属性(非常巧妙)。伪代码如下:
一个
2
三
四
五
六
七
defsave(obj):
return(obj。__class__,obj。__字典_ _)
defload(cls,属性):
obj=cls。__新__(cls)
obj。__词典_ _。更新(属性)
returnobj
如果想在序列化的过程中做一些额外的操作,比如保存对象的状态,可以使用pickle协议的神奇方法,最常见的有__setstate__()和__getstate__()。
安全问题(!)
在unpickle文档的开始,它说:永远不要解包一个未知来源的二进制文件。考虑以下代码:
一个
2
三
四
进口泡菜
pickle . loads(b cos \ n system \ n(S echo hello world \ ntR。)
编译
0
当这段代码解钩时,它导入os.system(),然后调用echo。没有副作用。但是如果是rm -rf /?
文档中给出的建议是在Unpickler.find_class()中实现检查逻辑。当需要全局变量时,必须调用方法。
一个
2
三
四
五
六
七
八
九
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
导入内置项
进口
进口泡菜
safe_builtins={
范围,
复杂,
设置,
冰冻集,
切片,
}
classRestrictedUnpickler(泡菜。拆线工):
deffind_class(自身,模块,名称):
#只允许内置的安全类。
if module== builtins and nameinsafe _ builtins:
returngetattr(内置,名称)
#禁止其他一切。
raisepickle。UnpicklingError(禁止使用全局 %s.%s )
(模块,名称))
defrestricted _负载:
类似于pickle.loads()的辅助函数。
returnRestrictedUnpickler(io。字节)。负载()
压缩
之后Pickle不会自动压缩。我觉得这个设计很好。解耦,pickle做pickle做的,压缩交给其他库。而且你还可以发现pickle之后的文件无法读取,但是内容还是以ascii码呈现,并不是乱码。您需要调用压缩库的compress。实际压缩后体积是之前的1/3左右,非常可观。
我目前知道的坑:
保持全局变量的可导入性有点困难。要面对的问题是:我今天腌制的东西,需要在未来的某一天打开。还能打开吗?
这里有几个版本:项目的版本,python的版本,pickle协议的版本,项目依赖的包版本。python版本和pickle版本很容易解决,我认为我可以放心地依赖它们的向后兼容性。它是主项目和版本以及从属版本。如果要备份的对象非常复杂,旧版本的备份可能无法与新版本兼容。可能的解决方案是完全锁定所有依赖项,比如记录它们的哈希值。如果要还原某个二进制序列,就要还原当时的具体依赖和项目的具体提交。
但是现在,我们的要求基本上是一个请求。响应对象。我认为我们可以依靠它们的向后兼容性。如果有一天请求有了突破性的改变,那么即使我们的泡菜是兼容的,代码也不会是兼容的。这时候就可以考虑其他策略了。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。