pickle是Python轻便的对象序列化工具。使用pickle可以方便地把python对象写入文件对象中,或者像soap那样在socket间传送。
按照python的一贯作风,类的成员在使用前不会分配和占用内存空间。这一点使用pickle可以看得很清楚。
例如有类矩形Rect
#文件Rect_Module.py
class Rect:
def __init__(self, a_width , a_height):
self.m_width = a_width
self.m_height = a_height
def get_area (self):
return self.m_width * self.m_height
def set_color(self,color):
self.m_color = color
该矩形类定义在__init__ 时候了两个成员高度m_height和m_width宽度,如果被设置颜色后,则又生成了m_color成员。
使用pickle来dump一个Rect对象:
#pickle_dump.py
import pickle
import Rect_Module
#生成一个3*4的矩形,然后pickle之
if __name__ == "__main__":
myrect = Rect_Module.Rect(3,4)
print "area is :" ,myrect.get_area()
fout = open("myrect.pkl","w")
pickle.dump(myrect,fout)
fout.close()
运行pickle_dump.py后,生成myrect.pkl文件,我们可以打开来看看:
(iRect_Module
Rect
p0
(dp1
S'm_height'
p2
I4
sS'm_width'
p3
I3
sb.
Pickle文件简单剖析
在pickle生成的文件中,很容易看到最前面红色和土黄色的分别是模块名和类名;
后面不远处是属性m_height和m_width,属性的后面是它的值:I4、I3是不是表示Integer的前缀?改变一下参数就知道了。
#pickle_dump.py
import pickle
import Rect_Module
if __name__ == "__main__":
myrect = Rect_Module.Rect(3.99999,4)
print "area is :" ,myrect.get_area()
fout = open("myrect.pkl","w")
pickle.dump(myrect,fout)
fout.close()
上面代码改变了传入参数的类型,希望dump出来的文件中有不同的类型前缀。dump出来的文件如下:
(iRect_Module
Rect
p0
(dp1
S'm_height'
p2
I4
sS'm_width'
p3
F3.9999899999999999
sb.
果不其然,传入3.99999构造Rect时,pickle文件中的值的字段变成了F3.9999****,这里F明显是Float的意思。实际上,如果需要pickle的对象成员为一个自定义类的类型,pickle文件里也会保留类名信息,以及类成员的内部结构。
Python的类属性动态加载
看了上面几个例子,我们会留意到Rect的set_color中涉及到了m_color成员实际上并没有生成,因为我们没有调用set_color方法。这是python的一个特性:成员只有在初次被引用的时候才会初始化。没有调用过的set_color对象是没有m_color属性的,如果你希望它一定有,那么只好在__init__中引用它了。这是python一个重要特点,是优是劣就见仁见智了。
下面设置一下颜色
#pickle_dump.py
import pickle
import Rect_Module
if __name__ == "__main__":
myrect = Rect_Module.Rect(3.99999,4)
print "area is :" ,myrect.get_area()
myrect.set_color("RED")
fout = open("myrect.pkl","w")
pickle.dump(myrect,fout)
fout.close()
得到的pickle文件
(iRect_Module
Rect
p0
(dp1
S'm_height'
p2
I4
sS'm_color'
p3
S'RED'
p4
sS'm_width'
p5
F3.9999899999999999
sb.
上文件的阴影部分清楚地指示了m_color文件被生成了。这里pickle生动地验证了python的“惰性”加载策略。
对象序列化有个重要的问题是:从文件中还原对象如何得到它的类信息。从上面的pickle文件看,文件中绝不可能存储对象的类的具体信息,只是存储了模块名和类名。
从pickle文件中装载对象非常简单,因为文件中已经有模块名和类名了,所以甚至无须import Rect_Module。这里尝试把上面例子生成的pickle文件读入:
#pickle_load.py
import pickle
if __name__ == "__main__":
fin = open("myrect.pkl")
load_from_file = pickle.load(fin)
print "area is :" ,load_from_file.get_area()
运行结果area is : 15.99996,证明对象加载正确。
如果把Rect_Module.py文件改名,就会出现“类型找不到”类的错误。
修改类接口
Python这样做可想而知是非常方便的,但这样做会出现一个非常严重的问题。一个pickle文件传到网络的另一端的时候,使用时需要把相应的类文件也传过去。类文件传过去以后,另一方的使用者就可以自由地改动类的部分属性和方法了。
下面通过试验看看是不是这样:
修改类的get_area方法,再load对象
class Rect:
def __init__(self, a_width , a_height):
self.m_width = a_width
self.m_height = a_height
def get_area (self):
return self.m_width * self.m_height * 2
def set_color(self,color):
self.m_color = color
改变了Rect类的get_area方法,面积的算法为长*宽*2。
此时再运行pickle_load.py,运行结果如下:
area is : 31.99992
惊喜地,类的方法被改变了,pickle文件中的对象依然能够正确加载。这个特性非常的灵活,而又非常的“不安全”。用户可以在理解了源代码的基础上,可以任意修改类的行为。这可能就是自由软件、自由语言的含义吧。
个人认为,在pickle文件中加入类的hash签名校验,便可以防止使用不同的类来加载pickle原本的对象。以python设计者的智商,这可能是考虑过的了,应该只是他们不喜欢对语言加以约束,让python更自由,灵活,简约
- Python+Selenium爬取动态加载页面(2)
注: 上一篇<Python+Selenium爬取动态加载页面(1)>讲了基本地如何获取动态页面的数据,这里再讲一个稍微复杂一点的数据获取全国水雨情网.数据的获取过程跟人手动获取过程类似,所 ...
- Python+Selenium爬取动态加载页面(1)
注: 最近有一小任务,需要收集水质和水雨信息,找了两个网站:国家地表水水质自动监测实时数据发布系统和全国水雨情网.由于这两个网站的数据都是动态加载出来的,所以我用了Selenium来完成我的数据获取. ...
- Python PhatomJS 和Selenium动态加载页面 获取图片内容
如果您觉得感兴趣的话,可以添加我的微信公众号:一步一步学Python{}这里的ma ...
- java 中能否使用 动态加载的类(Class.forName) 来做类型转换?
今天同事提出了一个问题: 将对象a 转化为类型b,b 的classpath 是在配置文件中配置的,需要在运行中使用Class.forName 动态load进来,因为之前从来没有想过类似的问题,所以懵掉 ...
- Java错误:找不到类文件或者未加载主类
使用java命令执行.class文件时,java只会查找环境变量CLASSPATH中的目录,并会不查找当前目录,所以只要把当前目录”."加入到CLASSPATH中就可以了.
- 【Java接口实现动态加载不同的类】
public interface Person { public double calcuMonthlySalary(double sal, int type); } publi ...
- 反射01 Class类的使用、动态加载类、类类型说明、获取类的信息
0 Java反射机制 反射(Reflection)是 Java 的高级特性之一,是框架实现的基础. 0.1 定义 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对 ...
- java反射机制与动态加载类
什么是java反射机制? 1.当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.我们认为java并不是动态语言,但是它却有一个非常突出的动态相关机制,俗称:反射. IT行业里这么说,没有 ...
随机推荐
- 在XAML代码中为节点树安装事件监听器
通过以下的演示样例代码,能够发现,我们能为随意的节点指定要监听的路由事件,而这个路由事件本身和这个元素可能根本就没有关系. <Window x:Class="Demo002.MainW ...
- 项目管理:关于SVN的实践
SVN是Subversion的简称,是一个开放源码的版本号控制系统. 合作开发的时候,对SVN的使用有3个软件:SVN的server端,SVNclient(也就是Tortoise SVN,寻常chec ...
- hdu 4105 贪心思想
淋漓尽致的贪心思想 波谷一定是一位数.波峰一位数不够大的时候加入到两位数就一定够大了的. 当在寻找波谷碰到零了就自然当成波谷. 当在寻找波峰时碰到零时,将前面的波谷加到前一个波峰上.让当前的零做波谷, ...
- ThinkPHP第十五天(setField、setInc、setDec、关联模型)
1.ThinkPHP中的比较特殊连贯操作 如果要更新某个字段可以用setField方法,比如M('user')->where('id=1')->setField('username','T ...
- [转]使用storyboard实现页面跳转,简单的数据传递
由于最近才接触到IOS,苹果已经建议storyboard来搭建所有界面了,于是我也追随时尚,直接开始使用storyboard.(不料在涉及到页面跳转的时候,遇到的问题是:点击后没有任何反应)众所周知, ...
- IOS FoundationKit (NSString) 知识汇总
1. interface 代表类声明,@implement 代表类实现,@encode 代表将object-c 中类型转换成指定字符串 2 当前char * 类型转化为字符串需要转化为NSStrin ...
- 带你一起Piu Piu Piu~
单刀直入,今天要讲的是自己写的一个WPF动画例子.我们在看下最终效果~ 最近在重看WPF编程宝典2010,在练习第15章动画性能例子时有了些想法.原始例子如下: 原始例子(打包了整个15章的) 它是 ...
- android中文字高亮设置案例
在android中我们有时候需要对一些标示性的文字进行高亮[用不同的颜色显示],例如微博中的@**等等...这些特效是通过SpannableString这个类来实现的 思路是将要显示的string进行 ...
- javascript - C++, Qt, QtWebKit: How to create an html rendering window so that your application would get callbacks from JS calls? - Stack Overflow
javascript - C++, Qt, QtWebKit: How to create an html rendering window so that your application woul ...
- poj2342 Anniversary party【树形dp】
转载请注明出处,谢谢:http://www.cnblogs.com/KirisameMarisa/p/4316097.html ---by 墨染之樱花 [题目链接]http://poj.org/p ...