python的类变量与实例变量以及__dict__属性

来源:互联网 发布:网络的好处 英语作文 编辑:程序博客网 时间:2024/05/16 02:36

关于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和ins2ins1 = cls()ins2 = cls()#用实例1为类变量重新赋值并打印print('#' * 10)ins1.clsvar = 20print(cls.clsvar)  # 输出结果为1print(ins1.clsvar)  # 输出结果为20print(ins2.clsvar)  # 输出结果为1#用类名为类变量重新赋值并打印print('#' * 10)cls.clsvar = 10print(cls.clsvar)  # 输出结果为10print(ins1.clsvar)  # 输出结果为20print(ins2.clsvar)  # 输出结果为10#这次直接给实例1没有在类中定义的变量赋值print('#' * 10)ins1.x = 11print(ins1.x)  # 输出结果为11#然后再用类名给类中没有定义的变量赋值print('#' * 10)cls.m = 21print(cls.m)  # 输出结果为21#再创建一个实例ins3,然后打印一下ins3的变量print('#' * 10)ins3 = cls()print(ins3.insvar)  # 输出结果为2print(ins3.clsvar)  # 输出结果为10print(ins3.m)  # 输出结果为21print(ins3.x)  # 报错AttributeError: cls instance has no attribute 'x'


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

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

 

 

 

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

复制代码
1 print cls.__dict__2 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 = 20print 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,            }
复制代码

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

复制代码
 1 class Dict2Obj: 2     def __init__(self,bokeyuan): 3         self.b = bokeyuan['b'] 4         self.o = bokeyuan['o'] 5         self.k = bokeyuan['k'] 6         self.e = bokeyuan['e'] 7         self.y = bokeyuan['y'] 8         self.u = bokeyuan['u'] 9         self.a = bokeyuan['a']10         self.n = bokeyuan['n']
复制代码

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

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


参考:http://www.cnblogs.com/duanv/p/5947525.html

原创粉丝点击