关于Python的实例变量与类变量,先来看一段可能颠覆世界观的例子

 #!/usr/bin/env python
# -*- coding: utf_8 -*-
# Date: 2016年10月10日
# Author:蔚蓝行 #首先创建一个类cls,这个类中包含一个值为1的类变量clsvar,一个值为2的实例变量insvar,
class cls:
clsvar = 1
def __init__(self):
self.insvar = 2 #创建类的实例ins1和ins2
ins1 = cls()
ins2 = cls() #用实例1为类变量重新赋值并打印
print '#'*10
ins1.clsvar = 20
print cls.clsvar #输出结果为1
print ins1.clsvar #输出结果为20
print ins2.clsvar #输出结果为1 #用类名为类变量重新赋值并打印
print '#'*10
cls.clsvar = 10
print cls.clsvar #输出结果为10
print ins1.clsvar #输出结果为20
print ins2.clsvar #输出结果为10 #这次直接给实例1没有在类中定义的变量赋值
print '#'*10
ins1.x = 11
print ins1.x #输出结果为11 #然后再用类名给类中没有定义的变量赋值
print '#'*10
cls.m = 21
print cls.m #输出结果为21 #再创建一个实例ins3,然后打印一下ins3的变量
print '#'*10
ins3 = cls()
print ins3.insvar #输出结果为2
print ins3.clsvar #输出结果为10
print ins3.m #输出结果为21
print ins3.x #报错AttributeError: cls instance has no attribute 'x'

看上去怪怪的,为什么会出现这种结果呢?这就要了解python中的__dict__属性了,__dict__是一个字典,键是属性名,值为属性值。

Python的实例有自己的__dict__,它对应的类也有自己的__dict__   (但是有些特殊的对象是没有__dict__属性的,这里不做讨论)

如果在程序的第15行处加上两句打印语句,打印类和实例1的__dict__属性,将会输出如下:

 print cls.__dict__
print ins1.__dict__ ###########输出##########

{'clsvar': 1, '__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x101bbc398>}

{'insvar': 2}

当打印类的__dict__属性时,列出了类cls所包含的属性,包括一些类内置属性和类变量clsvar以及构造方法__init__

而实例变量则包含在实例对象ins1的__dict__属性中,一个对象的属性查找顺序遵循首先查找实例对象自己,然后是类,接着是类的父类。

现在可以解释开头代码中的神秘现象了,再强调一遍,一个对象的属性查找顺序遵循首先查找实例对象自己,然后是类,接着是类的父类。

在第18行  ins1.clsvar = 20这句后面我们打印一下实例和类的__dict__属性

ins1.clsvar = 20
print ins1.__dict__
print cls.__dict__
###########输出##########

{'insvar': 2, 'clsvar': 20}

{'clsvar': 1, '__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x10c768398>}

可以看到,ins1.clsvar = 20这句只是在实例ins1的__dict__属性中增加了'clsvar': 20这一键值对,而类中的clsvar的值并没有改变,重要的事情说三遍:一个对象的属性查找顺序遵循首先查找实例对象自己,然后是类,接着是类的父类。当ins1在自己的__dict__中查找到了clsvar,就不会再向上查找,所以输出了值20。但是此时,cls类中的clsvar的值仍然为1。

但是当在第25行通过类名改变了类的clsvar之后,类的__dict__中的clsvar就被改变成10了,这时打印ins1的clsvar,由于之前第18行的原因,ins1在自己的__dict__中找到了clsvar,就输出了它自己的值20,而ins2自己的__dict__中没有clsvar,就向上查找类的__dict__,并找到了类的clsvar,值为10

第46行的ins3一直向上查找x属性都没有找到,就会抛出AttributeError

像32行和37行这样给类或实例设置属性,其实就是在他们各自的__dict__中添加了该属性,相信现在其他的神秘现象大家也可以自己解释了。

最后附上一个将字典转换成对象的小技巧,如果我们有一个字典如下:

bokeyuan={"b":1,
"o":2,
"k":3,
"e":4,
"y":5,
"u":6,
"a":7,
"n":8,
}

现在想将其转换为一个对象,通常会这样写:

 class Dict2Obj:
def __init__(self,bokeyuan):
self.b = bokeyuan['b']
self.o = bokeyuan['o']
self.k = bokeyuan['k']
self.e = bokeyuan['e']
self.y = bokeyuan['y']
self.u = bokeyuan['u']
self.a = bokeyuan['a']
self.n = bokeyuan['n']

但是在了解了__dict__属性之后可以这样写:

 class Dict2Obj:
def __init__(self,bokeyuan):
self.__dict__.update(bokeyuan)

python的类变量与实例变量以及__dict__属性的更多相关文章

  1. Python基础-类变量和实例变量

    Python基础-类变量和实例变量 写在前面 如非特别说明,下文均基于Python3 大纲: 1. 类变量和实例变量 在Python Tutorial中对于类变量和实例变量是这样描述的: Genera ...

  2. 【类不类二】Python的类变量与实例变量

    在研究类的时候,难免会有很多疑问,C论坛和博客园高手如云(不知道是不是也美女如云), 搜到了这篇博文,是介绍Python的类变量和实例变量的 ! 刚好在下对self.***这种形式的实例变 量不是很理 ...

  3. python(四)类变量和实例变量

    转载自[1] 实际这是个实例变量是否指向类变量的问题. python的类变量和实例变量,顾名思义,类变量是指跟类的变量,而实例变量,指跟类的具体实例相关联的变量,具体体现为self.x 等.实际要注意 ...

  4. python的类变量与实例变量

    python的类内部定义的变量 ,形式上没有区分实例变量和类变量(java的静态变量),测试结果如下: 

  5. Python中面向对象的一些关于类变量与实例变量的理解

    1. 要写出有意义的面向对象的代码,最核心的:类.对象.三大特性:继承.封装.多态 类变量与实例变量: class Student(): # 类变量 name = '张' age = 0 def __ ...

  6. python中的实例方法、静态方法、类方法、类变量和实例变量

    class MyTest: myname = 'peter' # add a instance attribute    def __init__(self, name):        self.n ...

  7. python的局部变量,全局变量,类变量,实例变量

    定义: a.全局变量:在模块内.在所有函数外面.在class外面,这就是全局变量. b.局部变量:在函数内.在class的方法内(未加self修饰的),这就是局部变量. c. 静态变量:在class内 ...

  8. 关于python类变量和实例变量

    今天在看python的类和实例的时候,突然发现了一个以前遗漏的点,也就是类变量和实例变量.首先需要理解一下类变量和实例变量的概念. 类全局变量:在类中定义,对类和由类生成的实例生效,如果通过方法对类变 ...

  9. python面向对象中类对象、实例对象、类变量、实例变量、类方法、实例方法、静态方法

    1. 类对象和实例对象 Python中一切皆对象,Python类本身也是一种对象,类定义完成后,会在当前作用域中定义一个以类名为名字的命名空间.类对象具有以下两种操作: 可以通过“类名()”的方式实例 ...

随机推荐

  1. 【Node.js】安装及使用

    Node.js是在Chrome的V8 JavaScript引擎上构建的JavaScript运行时.Node.js使用事件驱动的非阻塞I / O模型,使其轻量且高效.Node.js的软件包生态系统npm ...

  2. eclipse配置servlet错误

    可能是因为你的web.xml里的<url>映射的名字和servlet相同

  3. php,mysql存储过程的简单例子

    一.连接mysql 使用phpmyadmin: 打开test数据库: 二.创建存储过程 参数如图. 三.php中调用存储过程 <?php $user = "root"; // ...

  4. 深入理解SpringCloud与微服务构建学习总结

    说明:用时 from 2018-11-16 to 2018-11-23 七天 0 放在前面   什么是微服务?   微服务是一个分布式系统.微服务架构的风格,就是将单一程序开发成一个微服务,每个微服务 ...

  5. tar打包如何不打包某一个文件夹(排除某些文件夹)

    tar打包如何不打包某一个文件夹(排除某些文件夹) 问题描述: 最近想备份一下Tomcat运行的的功能文件,以防特殊情况的发生.但是在实际操作的过程中发现,可能是由于Unix/Linux版本太老的原因 ...

  6. Altera 在线资源使用

    Altera 在线资源使用 Altera 在线资源使用 1 1.Altera中文版 2 2.建立myaltera账户 获取官网信息与支持 2 3系统化的设计资源 2 3.1.设计实例 2 3.2.参考 ...

  7. MongoDB、MySQL

    我的电脑的系统Path:   D:\sqlite;D:\Program Files\MongoDB\Server\3.4\bin;%MYSQL_HOME%\bin;D:\Program Files\B ...

  8. 带权单源最短路[稀疏图](Dijkstra)

    因为是稀疏图,所以应当选择邻接表来存储 构造一个邻接表 这只是我的构造方法,有很多种更好的构造方法,大家可以自己去构造 typedef int vertex; typedef int WeightTy ...

  9. 安装过redis集群,重新做集群办法:

    二:找到问题:这个地方IP的问题,以上是正确的版本,以前有问题的版本的Ip是127.0.0.1, 原因是这个地方以前我没注释redis.conf文件中的bind 127.0.0.1 然后做集群时使用的 ...

  10. create-react-app脚手架中配置webpack的方法

    概述 create-react-app脚手架中的react-scripts能够(1)帮我们自动下载需要的webpack依赖:(2)自己写了一个nodejs服务端脚本代码:(3)使用express的Ht ...