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更自由,灵活,简约

转:从pickle看python类成员的动态加载和类的定位的更多相关文章

  1. Python+Selenium爬取动态加载页面(2)

    注: 上一篇<Python+Selenium爬取动态加载页面(1)>讲了基本地如何获取动态页面的数据,这里再讲一个稍微复杂一点的数据获取全国水雨情网.数据的获取过程跟人手动获取过程类似,所 ...

  2. Python+Selenium爬取动态加载页面(1)

    注: 最近有一小任务,需要收集水质和水雨信息,找了两个网站:国家地表水水质自动监测实时数据发布系统和全国水雨情网.由于这两个网站的数据都是动态加载出来的,所以我用了Selenium来完成我的数据获取. ...

  3. Python PhatomJS 和Selenium动态加载页面 获取图片内容

    如果您觉得感兴趣的话,可以添加我的微信公众号:一步一步学Python![](http://images2017.cnblogs.com/blog/993869/201711/993869-201711 ...

  4. eclipse运行一个类却运行的是另外一个类,报无法加载的类

    今天是用eclipse想运行一个a.java但是却加载是b.java文件,而且还报错:无法加载的主类 查了半天才发现a.java文件中:public static void main(){}这里的ma ...

  5. java 中能否使用 动态加载的类(Class.forName) 来做类型转换?

    今天同事提出了一个问题: 将对象a 转化为类型b,b 的classpath 是在配置文件中配置的,需要在运行中使用Class.forName 动态load进来,因为之前从来没有想过类似的问题,所以懵掉 ...

  6. Java错误:找不到类文件或者未加载主类

    使用java命令执行.class文件时,java只会查找环境变量CLASSPATH中的目录,并会不查找当前目录,所以只要把当前目录”."加入到CLASSPATH中就可以了.

  7. 【Java接口实现动态加载不同的类】

    public interface Person {       public double calcuMonthlySalary(double sal, int type);    }   publi ...

  8. 反射01 Class类的使用、动态加载类、类类型说明、获取类的信息

    0 Java反射机制 反射(Reflection)是 Java 的高级特性之一,是框架实现的基础. 0.1 定义 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对 ...

  9. java反射机制与动态加载类

    什么是java反射机制? 1.当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.我们认为java并不是动态语言,但是它却有一个非常突出的动态相关机制,俗称:反射. IT行业里这么说,没有 ...

随机推荐

  1. [HDU 4741]Save Labman No.004[计算几何][精度]

    题意: 求两条空间直线的距离,以及对应那条距离线段的两端点坐标. 思路: 有一个参数方程算最短距离的公式, 代入求即可. 但是这题卡精度... 用另外的公式(先算出a直线上到b最近的点p的坐标, 再算 ...

  2. 关于Windows Phone的资源文件Build Action属性

    最近一朋友问了一个问题,他想引用一个本地图片到页面上的Image控件,可是发现用Application的GetResourceStream得到的结果是个null值,当时第一个想到的就是他图片的Buil ...

  3. typedef使用

    1.利用typedef定义函数指针 代码简化,促进跨平台开发 typedef行为有点类似#define 宏,用其实际类型替代同义字.   不同点:typedef 在编译时被解释,因此让编译器来 应付超 ...

  4. JS 在html中的位置

    前言 当我了解完html在浏览器中的解析渲染流程后,反而又发现了新的困扰自己的问题. Q:即然html要渲染需要渲染树,而渲染树又需要DOMTree和CSSRuleTree,DOMTree需要解析HT ...

  5. 新建一个类并绑定一个activity

    1.新建一个类(.java 文件),继承Android.app.Activity 2.新建一个activity 文件 3.重写onCreate 方法,设置绑定activity 文件 @Override ...

  6. Android SQLite之乐学成语项目数据库存储

    一.SQLite是什么?为什么要用SQLite?SQLite有什么特点?(下面小编一 一解答) ①SQLite是一个轻量级的关系型数据库,运算速度快,占用资源少,很适合在移动设备上使用, 不仅支持 标 ...

  7. Android应用开发基础篇(11)-----ViewFlipper

    链接地址:http://www.cnblogs.com/lknlfy/archive/2012/03/01/2376067.html 一.概述 ViewFlipper这个部件是用来实现多页显示的,多页 ...

  8. JavaSE_ 网络编程 目录(26)

    JavaSE学习总结第26天_网络编程26.01 网络编程概述26.02 网络模型概述和图解26.03 网络编程三要素概述26.04 网络编程三要素之IP概述126.05 InetAddress类的概 ...

  9. 关于两次指针(struct型)传参数的问题

    这两天被struct传参给郁闷死了.今天终于解决了. 比如有一个struct如下: struct _ns1__Add_USCORESensorDataArray{ struct xsd__base64 ...

  10. set up blog on github

    http://www.ruanyifeng.com/blog/2012/08/blogging_with_jekyll.html