關於Python的實例變量與類變量,先來看一段可能顛覆世界觀的例子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__是一個字典,鍵是屬性名,值爲屬性值。code
Python的實例有本身的__dict__,它對應的類也有本身的__dict__ (可是有些特殊的對象是沒有__dict__屬性的,這裏不作討論)對象
若是在程序的第15行處加上兩句打印語句,打印類和實例1的__dict__屬性,將會輸出以下:it
print cls.__dict__ print ins1.__dict__ ###########輸出########## {'clsvar': 1, '__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x101bbc398>} {'insvar': 2}
當打印類的__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。module
可是當在第25行經過類名改變了類的clsvar以後,類的__dict__中的clsvar就被改變成10了,這時打印ins1的clsvar,因爲以前第18行的緣由,ins1在本身的__dict__中找到了clsvar,就輸出了它本身的值20,而ins2本身的__dict__中沒有clsvar,就向上查找類的__dict__,並找到了類的clsvar,值爲10date
第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.__dict__.update(bokeyuan)