python的类变量与实例变量及__dict__属性
2017-12-08 10:53
309 查看
关于Python的实例变量与类变量,先来看一段可能颠覆世界观的例子
#!/usr/bin/env python
# -*- coding: utf_8 -*-
# Date: 2016年10月10日
#首先创建一个类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
看上去怪怪的,为什么会出现这种结果呢?这就要了解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这句只是在实例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__中添加了该属性,相信现在其他的神秘现象大家也可以自己解释了。
最后附上一个将字典转换成对象的小技巧,如果我们有一个字典如下:
现在想将其转换为一个对象,通常会这样写:
#!/usr/bin/env python
# -*- coding: utf_8 -*-
# Date: 2016年10月10日
#首先创建一个类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']< 4000 /pre>但是在了解了__dict__属性之后可以这样写: class Dict2Obj: def __init__(self,bokeyuan): self.__dict__.update(bokeyuan)
相关文章推荐
- python的类变量与实例变量以及__dict__属性
- python的类变量与实例变量以及__dict__属性
- python的类变量与实例变量以及__dict__属性
- python的类变量与实例变量以及__dict__属性
- python的类变量与实例变量以及__dict__属性
- 【python】实例属性的显示方法-dir、__dict__
- python中类变量和实例变量__之类对象属性(类变量和函数)
- [python]“静态”变量:谈类属性和实例属性
- Python语法中容易混淆的地方-类属性/实例属性/公有变量/私有化变量
- 【再回首Python之美】【类】通过dir()和__dict__查看一个类的属性和一个实例对象的属性
- Python 类属性变量和全局变量
- python 变量作用域实例
- Python学习26:类属性vs实例属性
- python中类的学习:类属性,实例属性 __new__方法:单例模式
- 打印出python 当前全局变量和入口参数的所有属性
- 打印出python 当前全局变量和入口参数的所有属性
- Python变量作用范围实例分析
- iOS 成员变量,实例变量,属性变量的区别,联系
- python的类变量和成员变量用法实例教程