關於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)