python的類變量與實例變量以及__dict__屬性

關於Python的實例變量與類變量,先來看一段可能顛覆世界觀的例子python

 1 #!/usr/bin/env python
 2 # -*- coding: utf_8 -*-
 3 # Date: 2016年10月10日
 4 # Author:蔚藍行
 5 
 6 #首先建立一個類cls,這個類中包含一個值爲1的類變量clsvar,一個值爲2的實例變量insvar,
 7 class cls:
 8     clsvar = 1
 9     def __init__(self):
10         self.insvar = 2
11 
12 #建立類的實例ins1和ins2
13 ins1 = cls()
14 ins2 = cls()
15 
16 #用實例1爲類變量從新賦值並打印
17 print '#'*10
18 ins1.clsvar = 20
19 print cls.clsvar     #輸出結果爲1
20 print ins1.clsvar    #輸出結果爲20
21 print ins2.clsvar    #輸出結果爲1
22 
23 #用類名爲類變量從新賦值並打印
24 print '#'*10
25 cls.clsvar = 10
26 print cls.clsvar     #輸出結果爲10
27 print ins1.clsvar    #輸出結果爲20
28 print ins2.clsvar    #輸出結果爲10
29 
30 #此次直接給實例1沒有在類中定義的變量賦值
31 print '#'*10
32 ins1.x = 11
33 print ins1.x         #輸出結果爲11
34 
35 #而後再用類名給類中沒有定義的變量賦值
36 print '#'*10
37 cls.m = 21
38 print cls.m          #輸出結果爲21
39 
40 #再建立一個實例ins3,而後打印一下ins3的變量
41 print '#'*10
42 ins3 = cls()
43 print ins3.insvar    #輸出結果爲2
44 print ins3.clsvar    #輸出結果爲10
45 print ins3.m         #輸出結果爲21
46 print ins3.x         #報錯AttributeError: cls instance has no attribute 'x'

看上去怪怪的,爲何會出現這種結果呢?這就要了解python中的__dict__屬性了,__dict__是一個字典,鍵是屬性名,值爲屬性值。spa

Python的實例有本身的__dict__,它對應的類也有本身的__dict__   (可是有些特殊的對象是沒有__dict__屬性的,這裏不作討論)code

 

 

 

若是在程序的第15行處加上兩句打印語句,打印類和實例1的__dict__屬性,將會輸出以下:對象

1 print cls.__dict__
2 print ins1.__dict__

###########輸出##########

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

{'insvar': 2}it

當打印類的__dict__屬性時,列出了類cls所包含的屬性,包括一些類內置屬性和類變量clsvar以及構造方法__init__io

而實例變量則包含在實例對象ins1的__dict__屬性中,一個對象的屬性查找順序遵循首先查找實例對象本身,而後是類,接着是類的父類。function

 

 

 

 

如今能夠解釋開頭代碼中的神祕現象了,再強調一遍,一個對象的屬性查找順序遵循首先查找實例對象本身,而後是類,接着是類的父類。class

在第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,     
       }

如今想將其轉換爲一個對象,一般會這樣寫:

 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)  
相關文章
相關標籤/搜索