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

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