什么是静态字段

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

  

  我们看上面的例子,这里的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 = name
12
13 #类的实例化,分别实例化出了两个对象father_obj1,father_obj2
14 father_obj1 = father('obj1')
15 father_obj2 = father('obj2')
16
17 #类调用
18 print 'father.money:',father.money
19 #对象调用
20 print 'father_obj1.money:',father_obj1.money
21 print 'father_obj2.money:',father_obj2.money
22
23 #使用类调用修改
24 father.money = father.money + 1000
25 print 'father.money:',father.money
26 print 'father_obj1.money:',father_obj1.money
27 print 'father_obj2.money:',father_obj2.money
28
29 #使用对象调用修改
30 father_obj1.money = father_obj1.money + 1
31 father_obj2.money = father_obj2.money + 2
32 print 'father.money:',father.money
33 print 'father_obj1.money:',father_obj1.money
34 print 'father_obj2.money:',father_obj2.money
35
36 father.money = father.money + 66
37 print 'father.money:',father.money
38 print 'father_obj1.money:',father_obj1.money
39 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 = name
12
13 #类的实例化,分别实例化出了两个对象father_obj1,father_obj2
14 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'] + 1000
24 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'] + 1
30 father_obj2.money['money'] = father_obj2.money['money'] + 2
31 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'] + 66
36 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 = name
12
13 class Son1(father):
14     pass
15
16 class Son2(father):
17     pass
18
19 class GrandSon(Son1,Son2):
20     pass
21
22 print 'father.money : ',father.money
23 print 'Son1.money : ',Son1.money
24 print 'Son2.money : ',Son2.money
25 print 'GrandSon.money : ',GrandSon.money
26 print '*'*25
27 father.money += 1000
28 print 'father.money : ',father.money
29 print 'Son1.money : ',Son1.money
30 print 'Son2.money : ',Son2.money
31 print 'GrandSon.money : ',GrandSon.money
32 print '*'*25
33 Son1.money += 100
34 Son2.money += 200
35 print 'father.money : ',father.money
36 print 'Son1.money : ',Son1.money
37 print 'Son2.money : ',Son2.money
38 print 'GrandSon.money : ',GrandSon.money
39 print '*'*25
40 GrandSon.money += 1
41 print 'father.money : ',father.money
42 print 'Son1.money : ',Son1.money
43 print 'Son2.money : ',Son2.money
44 print 'GrandSon.money : ',GrandSon.money
45 print '*'*25
46 father.money += 2000
47 print 'father.money : ',father.money
48 print 'Son1.money : ',Son1.money
49 print 'Son2.money : ',Son2.money
50 print 'GrandSon.money : ',GrandSon.money

demoCode

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

  

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

 

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

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

python的类和对象——类的静态字段番外篇相关推荐

  1. python接口自动化(三十二)--Python发送邮件(常见四种邮件内容)番外篇——上(详解)...

    简介 本篇文章与前边没有多大关联,就是对前边有关发邮件的总结和梳理.在写脚本时,放到后台运行,想知道执行情况,会通过邮件.SMS(短信).飞信.微信等方式通知管理员,用的最多的是邮件.在linux下, ...

  2. python接口自动化(三十二)--Python发送邮件(常见四种邮件内容)番外篇——上

    简介 本篇文章与前边没有多大关联,就是对前边有关发邮件的总结和梳理.在写脚本时,放到后台运行,想知道执行情况,会通过邮件.SMS(短信).飞信.微信等方式通知管理员,用的最多的是邮件.在linux下, ...

  3. 用python内置函数算复杂度吗_番外篇: Python 面试感受

    醒来有人说我刁难面试者, 我来解释一下, 我的面试环节一般是最后一个环节才会进行 python 基础的面试. 之前都是项目交流, 进入到最后这个环节的, 都是我认为项目 OK 的, 我对他的能力也是认 ...

  4. Kotlin 学习笔记(七)—— Kotlin类与对象之属性与字段

    Kotlin 学习笔记(七)-- Kotlin类与对象之属性与字段 Kotlin学习笔记系列教程 Kotlin 学习笔记(一)-- 概述.学习曲线.开发工具.参考资料 Kotlin 学习笔记(二)-- ...

  5. 1~22(面向编程+ES6中的类和对象+类的继承+面向对象版tab栏切换)

    1 面向对象编程介绍 1.1 两大编程思想 面向过程 面向对象 1.2 面向过程编程POP(Process-oriented programming) 面向过程就是分析出解决问题所需要的步骤,然后用函 ...

  6. 给深度学习入门者的Python快速教程 - 番外篇之Python-OpenCV

    转载自:https://zhuanlan.zhihu.com/p/24425116 本篇是前面两篇教程:给深度学习入门者的Python快速教程 - 基础篇 给深度学习入门者的Python快速教程 - ...

  7. 通过游戏编程学Python(番外篇)— 单词小测验

    通过游戏编程学Python 通过游戏编程学Python(6)- 英汉词典.背单词 通过游戏编程学Python(番外篇)- 乱序成语.猜单词 通过游戏编程学Python(5)- 猜成语(下) 通过游戏编 ...

  8. python爬虫进程和线程_python爬虫番外篇(一)进程,线程的初步了解-阿里云开发者社区...

    整理这番外篇的原因是希望能够让爬虫的朋友更加理解这块内容,因为爬虫爬取数据可能很简单,但是如何高效持久的爬,利用进程,线程,以及异步IO,其实很多人和我一样,故整理此系列番外篇 一.进程 程序并不能单 ...

  9. #3使用html+css+js制作网页 番外篇 使用python flask 框架 (I)

    #3使用html+css+js制作网页 番外篇 使用python flask 框架(I 第一部) 0. 本系列教程 1. 准备 a.python b. flask c. flask 环境安装 d. f ...

最新文章

  1. 组合游戏系列5: 井字棋、五子棋AlphaGo Zero 算法实战
  2. 牛逼!Docker遇到Intellij IDEA,再次解放了生产力~
  3. GPU算力免费用?百度AI Studio两周年惊喜活动开启
  4. 卷积神经网络之 - Lenet
  5. 【Git】处理 Unable to access ‘https://github.com’: OpenSSL SSL_read: Connection was reset, errno 10054
  6. 程序员为什么应该旗帜鲜明地反对“最佳实践”?
  7. wordpress主题_2014年十大免费WordPress主题
  8. unity3d 改变脚本名称_Unity3D脚本中文教程
  9. 人工智能十大算法及应用,十大人工智能算法公司
  10. 服务器ghost备份后无法进入系统还原,如下图,电脑开不起来了,重新ghost恢复备份的系统后启动依旧蓝屏,怎么办?...
  11. 关于丹佛机场行李系统分析
  12. Access control configuration prevents your request from being allo
  13. N32926 24小时连续测试720p, h.264 IPCAM功能,为什么基本不发热呢?
  14. C++高频面试问题总结
  15. 我始终相信努力奋斗的意义
  16. R语言cowplot介绍——把不同的图像拼接到一起
  17. 通俗易懂的磁盘分区教程,图文并茂简单明了!
  18. C语言中数组作为函数的形参
  19. Nginx代理POP协议之安装和配置
  20. 两年Java开发工作经验面试总结

热门文章

  1. apache 站点安全
  2. monodroid发布的最新版本
  3. cannot restore segment prot after reloc
  4. python3.X 使用schedule实现定时任务
  5. ios 小数保留位数
  6. 解决ifconfig命令未找到
  7. 安装Maltego默认插件
  8. 回复 集赞 抢 《Apple Watch 苹果开发教程》活动开始了!!!
  9. 搭建渗透测试环境选自KaliLinux无线网络渗透测试教程
  10. mysql主主和F5高可用_MYSQL 主主热备高可用方案与实现