博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python的类和对象——类的静态字段番外篇
阅读量:4598 次
发布时间:2019-06-09

本文共 5660 字,大约阅读时间需要 18 分钟。

什么是静态字段

  在开始之前,先上图,解释一下什么是类的静态字段(我有的时候会叫它类的静态变量,总之说的都是它。后面大多数情况可能会简称为类变量。):

  

  我们看上面的例子,这里的money就是静态字段,首先看它的位置,是在father类中,而不是在__init__中。那么一个小小的静态字段,我为什么要特意写一篇番外给它呢?耐着性子看下去,你就会发现一个小小的类变量,却折射出了整个类的世界。

  首先我们先来解释一下什么叫做静态字段:

        

  我们看上面的例子,左中右三张图,左边是纯净的代码,中间是我给代码加上的内存加载过程,右边是执行结果。我们在这里先看中间的图,来看这个文件加载的过程。

  1.将类存入了内存 2.将money变量放入了内存 3.将__init__方法的地址放入了内存

  接下来我们执行了一个__dict__方法,我们看右边图中现实的执行结果,发现这个时候内存中已经存入了money这个变量,它随着这个程序的执行产生,随着程序的结束而消失,这样和程序‘共存亡’的字段,我们就叫它静态字段。它就像是一个全局变量,不属于任何一个对象,我们可以直接使用类来调用,也可以在对象使用方法的时候使用它。它是对象共享的变量,存在类的内存里。

静态字段的调用方法

  刚刚我们知道了什么是静态字段,现在我们就来看看静态字段是怎么使用的?

       

  上面给出了两种使用方式,类调用和对象调用,哎?看起来好像可以哎!我们再来修改一下类变量瞧瞧:

       

  我们看,当我们使用 类名.静态字段名 修改类变量之后,使用类或者对象去调用这个静态字段,发现它们都产生了变化。好像一切都在我们的预料之中哎,这样的话对象和类都可以使用类变量的样子!如果你们真的信了那就太天真了。。。看看下面这个例子:

        

  看上面的图,我是接着上面的例子写的,黄框框里是我加上的内容,我们结果中最后打印出来的内容,哎?我们看到了什么?好像对象调用的类变量只是针对各自的对象发生了改变,并没有改变类中money变量的值,说好的全局变量呢?这个现象是怎么发生的呢?我们不防来推理一下:

        

  看上面两张图,左边是正常的逻辑,当我们类的内存中有一个静态字段的时候,我们使用类去调用这个字段,自然找到的是静态字段,当我们使用对象去调用的时候,这个对象指针先在自己的内存里找了找,发现没找到,于是就用对象中维护的类指针到类的内存中去找,果然找到了money,于是欢欢喜喜的打印了出来,我们也如愿以偿的看到了想要的结果。当我们使用 类 去调用这个静态字段进行修改的时候,我们修改的是 类 的内存中维护的money字段,所以并没有影响上述过程。

  再看右边这张图,当我们使用对象去调用并改变一个类的静态字段的时候,它们在自己的内存中并没有money字段,所以还是通过类指针到类内存中去找,但是当它们找到之后,就会在自己的内存空间开辟一块空间来存储对这个静态字段修改后的结果。所以,这个时候类中的静态字段就不会被改变,而两个对象中的money字段也就不会互相影响了。

       

  这个时候我们在刚刚的基础上再加上一段代码,来看执行的结果,我们发现这个时候再使用类变量对类的静态变量进行修改,分别看看类和对象中这个变量的变化,我们发现对象中的变量没有按照我们期待的那样发生改变,这也验证了我们的猜想,因为这个时候对象的内存中已经有了money变量,它们就不愿意舍近求远的到类内存中去取变量来给我们显示了。

1 #!/usr/bin/env python 2 #-*-coding:utf-8-*- 3 __author__ = 'Eva_J' 4 class father(object): 5  6     #静态字段 7     money = 10000 8     def __init__(self,name): 9 10         #普通字段11         self.name = name12 13 #类的实例化,分别实例化出了两个对象father_obj1,father_obj214 father_obj1 = father('obj1')15 father_obj2 = father('obj2')16 17 #类调用18 print 'father.money:',father.money19 #对象调用20 print 'father_obj1.money:',father_obj1.money21 print 'father_obj2.money:',father_obj2.money22 23 #使用类调用修改24 father.money = father.money + 100025 print 'father.money:',father.money26 print 'father_obj1.money:',father_obj1.money27 print 'father_obj2.money:',father_obj2.money28 29 #使用对象调用修改30 father_obj1.money = father_obj1.money + 131 father_obj2.money = father_obj2.money + 232 print 'father.money:',father.money33 print 'father_obj1.money:',father_obj1.money34 print 'father_obj2.money:',father_obj2.money35 36 father.money = father.money + 6637 print 'father.money:',father.money38 print 'father_obj1.money:',father_obj1.money39 print 'father_obj2.money:',father_obj2.money
demo Code

  但是,我们变量类型换乘字典试试看,结果又不一样了,代码在下面,自己粘回去执行吧,这里就不给你们贴花花绿绿的图了:

    

1 #!/usr/bin/env python 2 #-*-coding:utf-8-*- 3 __author__ = 'Eva_J' 4 class father(object): 5  6     #静态字段 7     money = {
'money':10000} 8 def __init__(self,name): 9 10 #普通字段11 self.name = name12 13 #类的实例化,分别实例化出了两个对象father_obj1,father_obj214 father_obj1 = father('obj1')15 father_obj2 = father('obj2')16 #类调用17 print 'father.money:',father.money['money']18 #对象调用19 print 'father_obj1.money:',father_obj1.money['money']20 print 'father_obj2.money:',father_obj2.money['money']21 22 #使用类调用修改23 father.money['money'] = father.money['money'] + 100024 print 'father.money:',father.money['money']25 print 'father_obj1.money:',father_obj1.money['money']26 print 'father_obj2.money:',father_obj2.money['money']27 28 #使用对象调用修改29 father_obj1.money['money'] = father_obj1.money['money'] + 130 father_obj2.money['money'] = father_obj2.money['money'] + 231 print 'father.money:',father.money['money']32 print 'father_obj1.money:',father_obj1.money['money']33 print 'father_obj2.money:',father_obj2.money['money']34 35 father.money['money'] = father.money['money'] + 6636 print 'father.money:',father.money['money']37 print 'father_obj1.money:',father_obj1.money['money']38 print 'father_obj2.money:',father_obj2.money['money']
demo Code

  为什么?这就和不同数据类型维护的指针有关系了。在这里不详细的赘述。

  偷懒的同学看这里→_→ :我们只需要记住,在使用类的静态变量的时候,必须要用类名来调用和修改。它才会永远被类和对象共享。

从类的继承这个角度来看看静态字段

  刚刚我们已经知道了对象和类中静态字段的存储及调用过程,下面我们就从类的继承这个角度来看看静态字段:

1 #!/usr/bin/env python 2 #-*-coding:utf-8-*- 3 __author__ = 'Eva_J' 4 class father(object): 5  6     #静态字段 7     money = 10000 8     def __init__(self,name): 9 10         #普通字段11         self.name = name12 13 class Son1(father):14     pass15 16 class Son2(father):17     pass18 19 class GrandSon(Son1,Son2):20     pass21 22 print 'father.money : ',father.money23 print 'Son1.money : ',Son1.money24 print 'Son2.money : ',Son2.money25 print 'GrandSon.money : ',GrandSon.money26 print '*'*2527 father.money += 100028 print 'father.money : ',father.money29 print 'Son1.money : ',Son1.money30 print 'Son2.money : ',Son2.money31 print 'GrandSon.money : ',GrandSon.money32 print '*'*2533 Son1.money += 10034 Son2.money += 20035 print 'father.money : ',father.money36 print 'Son1.money : ',Son1.money37 print 'Son2.money : ',Son2.money38 print 'GrandSon.money : ',GrandSon.money39 print '*'*2540 GrandSon.money += 141 print 'father.money : ',father.money42 print 'Son1.money : ',Son1.money43 print 'Son2.money : ',Son2.money44 print 'GrandSon.money : ',GrandSon.money45 print '*'*2546 father.money += 200047 print 'father.money : ',father.money48 print 'Son1.money : ',Son1.money49 print 'Son2.money : ',Son2.money50 print 'GrandSon.money : ',GrandSon.money
demoCode

  上面这段代码的执行结果是这样的:

   

  原理在下面,当我们使用创建类的时候,每个基类和派生类都会产生自己的内存,一开始派生类中没有money变量,所以在调用的时候它们通过类中维护的指针都顺利地找到了父类中的money变量,返回给了我们,但是当我们使用 派生类名.静态字段名 对派生类中的静态字段进行修改的时候,它们就默默地把修改的结果存在了自己的内存空间内。所以在之后的调用中就不千里迢迢的去父类中找这个变量了。其实和上面的道理是一样一样哒!

 

  偷懒的同学看这里→_→ :我们只需要记住,在使用类的静态变量的时候,如果我们希望基类和各派生类的静态字段被共享,必须要用基类名来调用和修改。  

  到这里关于类的静态字段的内容就全部讲完了,简简单单的一个静态字段,竟然囊括了这么多知识点,是不是值得我们花一点点时间来搞清楚呢?

转载于:https://www.cnblogs.com/Eva-J/p/5044411.html

你可能感兴趣的文章
矩阵乘法运算
查看>>
Java 日志组件(三)
查看>>
iphone中button按钮显示为圆形解决
查看>>
SharedPreferences.Editor 的apply()与commit()方法的区别
查看>>
页面编码
查看>>
gulpfile.js(编译sass,压缩图片,自动刷新浏览器)
查看>>
用于解决用户多线路访问的nginx cross isp module
查看>>
vs启动项目提示Web 服务器被配置为不列出此目录的内容。
查看>>
CF140E New Year Garland
查看>>
LeetCode--Remove Linked List Elements--JavaScript
查看>>
[android]深入理解findViewById原理
查看>>
实验四
查看>>
easypoi 一行代码搞定excel导入导出
查看>>
JumpServer安装与使用
查看>>
前端构建工具gulp
查看>>
ref:CodeIgniter框架内核设计缺陷可能导致任意代码执行
查看>>
1475.ip数据包解析
查看>>
JAVA 笔记(一)
查看>>
jdk+Tomcat部署安装
查看>>
js 循环读取 json的值
查看>>