1. 程式人生 > >python的類和對象(類的靜態字段)

python的類和對象(類的靜態字段)

字典 可能 qbit fit pkg 繼承 方式 con sel


轉自:http://www.cnblogs.com/Eva-J/p/5044411.html

什麽是靜態字段

  在開始之前,先上圖,解釋一下什麽是類的靜態字段(我有的時候會叫它類的靜態變量,總之說的都是它。後面大多數情況可能會簡稱為類變量。):

  技術分享圖片

  我們看上面的例子,這裏的money就是靜態字段,首先看它的位置,是在father類中,而不是在__init__中。那麽一個小小的靜態字段,我為什麽要特意寫一篇番外給它呢?耐著性子看下去,你就會發現一個小小的類變量,卻折射出了整個類的世界。

  首先我們先來解釋一下什麽叫做靜態字段:

  技術分享圖片 技術分享圖片 技術分享圖片

  我們看上面的例子,左中右三張圖,左邊是純凈的代碼,中間是我給代碼加上的內存加載過程,右邊是執行結果。我們在這裏先看中間的圖,來看這個文件加載的過程。

  1.將類存入了內存 2.將money變量放入了內存 3.將__init__方法的地址放入了內存

  接下來我們執行了一個__dict__方法,我們看右邊圖中現實的執行結果,發現這個時候內存中已經存入了money這個變量,它隨著這個程序 的執行產生,隨著程序的結束而消失,這樣和程序‘共存亡’的字段,我們就叫它靜態字段。它就像是一個全局變量,不屬於任何一個對象,我們可以直接使用類來 調用,也可以在對象使用方法的時候使用它。它是對象共享的變量,存在類的內存裏。

靜態字段的調用方法

  剛剛我們知道了什麽是靜態字段,現在我們就來看看靜態字段是怎麽使用的?

  技術分享圖片 技術分享圖片

  上面給出了兩種使用方式,類調用和對象調用,哎?看起來好像可以哎!我們再來修改一下類變量瞧瞧:

  技術分享圖片 技術分享圖片

  我們看,當我們使用 類名.靜態字段名 修改類變量之後,使用類或者對象去調用這個靜態字段,發現它們都產生了變化。好像一切都在我們的預料之中哎,這樣的話對象和類都可以使用類變量的樣子!如果你們真的信了那就太天真了。。。看看下面這個例子:

  技術分享圖片 技術分享圖片

  看上面的圖,我是接著上面的例子寫的,黃框框裏是我加上的內容,我們結果中最後打印出來的內容,哎?我們看到了什麽?好像對象調用的類變量只是 針對各自的對象發生了改變,並沒有改變類中money變量的值,說好的全局變量呢?這個現象是怎麽發生的呢?我們不防來推理一下:

  技術分享圖片 技術分享圖片

  看上面兩張圖,左邊是正常的邏輯,當我們類的內存中有一個靜態字段的時候,我們使用類去調用這個字段,自然找到的是靜態字段,當我們使用對象去 調用的時候,這個對象指針先在自己的內存裏找了找,發現沒找到,於是就用對象中維護的類指針到類的內存中去找,果然找到了money,於是歡歡喜喜的打印 了出來,我們也如願以償的看到了想要的結果。當我們使用 類 去調用這個靜態字段進行修改的時候,我們修改的是 類 的內存中維護的money字段,所以並沒有影響上述過程。

  再看右邊這張圖,當我們使用對象去調用並改變一個類的靜態字段的時候,它們在自己的內存中並沒有money字段,所以還是通過類指針到類內存中 去找,但是當它們找到之後,就會在自己的內存空間開辟一塊空間來存儲對這個靜態字段修改後的結果。所以,這個時候類中的靜態字段就不會被改變,而兩個對象 中的money字段也就不會互相影響了。

  技術分享圖片 技術分享圖片

  這個時候我們在剛剛的基礎上再加上一段代碼,來看執行的結果,我們發現這個時候再使用類變量對類的靜態變量進行修改,分別看看類和對象中這個變 量的變化,我們發現對象中的變量沒有按照我們期待的那樣發生改變,這也驗證了我們的猜想,因為這個時候對象的內存中已經有了money變量,它們就不願意 舍近求遠的到類內存中去取變量來給我們顯示了。

技術分享圖片 技術分享圖片
#!/usr/bin/env python
#-*-coding:utf-8-*-
__author__ = ‘Eva_J‘
class father(object):

    #靜態字段
    money = 10000
    def __init__(self,name):

        #普通字段
        self.name = name

#類的實例化,分別實例化出了兩個對象father_obj1,father_obj2
father_obj1 = father(‘obj1‘)
father_obj2 = father(‘obj2‘)

#類調用
print ‘father.money:‘,father.money
#對象調用
print ‘father_obj1.money:‘,father_obj1.money
print ‘father_obj2.money:‘,father_obj2.money

#使用類調用修改
father.money = father.money + 1000
print ‘father.money:‘,father.money
print ‘father_obj1.money:‘,father_obj1.money
print ‘father_obj2.money:‘,father_obj2.money

#使用對象調用修改
father_obj1.money = father_obj1.money + 1
father_obj2.money = father_obj2.money + 2
print ‘father.money:‘,father.money
print ‘father_obj1.money:‘,father_obj1.money
print ‘father_obj2.money:‘,father_obj2.money

father.money = father.money + 66
print ‘father.money:‘,father.money
print ‘father_obj1.money:‘,father_obj1.money
print ‘father_obj2.money:‘,father_obj2.money

demo Code
技術分享圖片

但是,我們變量類型換乘字典試試看,結果又不一樣了,代碼在下面,自己粘回去執行吧,這裏就不給你們貼花花綠綠的圖了:

技術分享圖片 技術分享圖片
#!/usr/bin/env python
#-*-coding:utf-8-*-
__author__ = ‘Eva_J‘
class father(object):

    #靜態字段
    money = {‘money‘:10000}
    def __init__(self,name):

        #普通字段
        self.name = name

#類的實例化,分別實例化出了兩個對象father_obj1,father_obj2
father_obj1 = father(‘obj1‘)
father_obj2 = father(‘obj2‘)
#類調用
print ‘father.money:‘,father.money[‘money‘]
#對象調用
print ‘father_obj1.money:‘,father_obj1.money[‘money‘]
print ‘father_obj2.money:‘,father_obj2.money[‘money‘]

#使用類調用修改
father.money[‘money‘] = father.money[‘money‘] + 1000
print ‘father.money:‘,father.money[‘money‘]
print ‘father_obj1.money:‘,father_obj1.money[‘money‘]
print ‘father_obj2.money:‘,father_obj2.money[‘money‘]

#使用對象調用修改
father_obj1.money[‘money‘] = father_obj1.money[‘money‘] + 1
father_obj2.money[‘money‘] = father_obj2.money[‘money‘] + 2
print ‘father.money:‘,father.money[‘money‘]
print ‘father_obj1.money:‘,father_obj1.money[‘money‘]
print ‘father_obj2.money:‘,father_obj2.money[‘money‘]

father.money[‘money‘] = father.money[‘money‘] + 66
print ‘father.money:‘,father.money[‘money‘]
print ‘father_obj1.money:‘,father_obj1.money[‘money‘]
print ‘father_obj2.money:‘,father_obj2.money[‘money‘]

demo Code
技術分享圖片

技術分享圖片

偷懶的同學看這裏→_→ :我們只需要記住,在使用類的靜態變量的時候,必須要用類名來調用和修改。它才會永遠被類和對象共享。

從類的繼承這個角度來看看靜態字段

  剛剛我們已經知道了對象和類中靜態字段的存儲及調用過程,下面我們就從類的繼承這個角度來看看靜態字段:

技術分享圖片
 1 #!/usr/bin/env python
 2 #-*-coding:utf-8-*-
 3 __author__ = ‘Eva_J‘
 4 class father(object):
 5 
 6     #靜態字段
 7     money = 10000
 8     def __init__(self,name):
 9 
10         #普通字段
11         self.name = name
12 
13 class Son1(father):
14     pass
15 
16 class Son2(father):
17     pass
18 
19 class GrandSon(Son1,Son2):
20     pass
21 
22 print ‘father.money : ‘,father.money
23 print ‘Son1.money : ‘,Son1.money
24 print ‘Son2.money : ‘,Son2.money
25 print ‘GrandSon.money : ‘,GrandSon.money
26 print ‘*‘*25
27 father.money += 1000
28 print ‘father.money : ‘,father.money
29 print ‘Son1.money : ‘,Son1.money
30 print ‘Son2.money : ‘,Son2.money
31 print ‘GrandSon.money : ‘,GrandSon.money
32 print ‘*‘*25
33 Son1.money += 100
34 Son2.money += 200
35 print ‘father.money : ‘,father.money
36 print ‘Son1.money : ‘,Son1.money
37 print ‘Son2.money : ‘,Son2.money
38 print ‘GrandSon.money : ‘,GrandSon.money
39 print ‘*‘*25
40 GrandSon.money += 1
41 print ‘father.money : ‘,father.money
42 print ‘Son1.money : ‘,Son1.money
43 print ‘Son2.money : ‘,Son2.money
44 print ‘GrandSon.money : ‘,GrandSon.money
45 print ‘*‘*25
46 father.money += 2000
47 print ‘father.money : ‘,father.money
48 print ‘Son1.money : ‘,Son1.money
49 print ‘Son2.money : ‘,Son2.money
50 print ‘GrandSon.money : ‘,GrandSon.money
51 
52 demoCode
技術分享圖片

上面這段代碼的執行結果是這樣的:

  技術分享圖片

  原理在下面,當我們使用創建類的時候,每個基類和派生類都會產生自己的內存,一開始派生類中沒有money變量,所以在調用的時候它們通過類中 維護的指針都順利地找到了父類中的money變量,返回給了我們,但是當我們使用 派生類名.靜態字段名 對派生類中的靜態字段進行修改的時候,它們就默默地把修改的結果存在了自己的內存空間內。所以在之後的調用中就不千裏迢迢的去父類中找這個變量了。其實和 上面的道理是一樣一樣噠!

技術分享圖片 技術分享圖片

  偷懶的同學看這裏→_→ :我們只需要記住,在使用類的靜態變量的時候,如果我們希望基類和各派生類的靜態字段被共享,必須要用基類名來調用和修改。  

  到這裏關於類的靜態字段的內容就全部講完了,簡簡單單的一個靜態字段,竟然囊括了這麽多知識點,是不是值得我們花一點點時間來搞清楚呢?

python的類和對象(類的靜態字段)