Python 中的引用和類屬性的理解

來源:互聯網
上載者:User
最近對Python 的對象引用機制稍微研究了一下,留下筆記,以供查閱。

首先有一點是明確的:「Python 中一切皆對象」。

那麼,這到底意味著什麼呢?

如下代碼:

#!/usr/bin/env pythona = [0, 1, 2] # 來個簡單的list# 最初,list 和其中各個元素的id 是這樣的。print 'origin'print id(a),afor x in a:    print id(x), xprint '----------------------'# 我們把第一個元素改改print 'after change a[0]'a[0] = 4print id(a),afor x in a:    print id(x), xprint '----------------------'# 我們再把第二個元素改改print 'after change a[1]'a[1] = 5print id(a),afor x in a:    print id(x), xprint '----------------------'# 回頭看看直接寫個0 ,id是多少print 'how about const 0?'print id(0), 0

運行結果如下:

PastgiftMacbookPro:python pastgift$ ./refTest.py Origin4299760200 [0, 1, 2]4298181328 04298181304 14298181280 2----------------------after change a[0]4299760200 [4, 1, 2]4298181232 44298181304 14298181280 2----------------------after change a[1]4299760200 [4, 5, 2]4298181232 44298181208 54298181280 2----------------------how about const 0?4298181328 0

從「Origin」部分來看,list 中各個元素的地址之間都正好相差24,依次指向各自的資料——這讓我想到了數組。

當修改a[0] 的值之後,發現,a[0] 的地址發生了變化。也就是說,指派陳述式實際上只是讓a[0] 重新指向另一個對象而已。此外,還注意到,a[0] 的地址和a[2]的地址相差48(2個24)。

當再次修改a[1] 之後,同樣地,a[1] 的地址也發生變化,有趣的是,這次a[1] 的地址和a[0] 的地址又相差24,和原先的a[2] 相差72(3個24)。

最後,當直接把數字0的地址列印出來後,發現它的地址和最開始的a[0] 的地址完全一樣。

至此,基本可以說明,就算是list 中的元素,其實也是引用。修改list 中的元素,實際上還是在修改引用而已。

對於Python 中類屬性,有人提到過「類屬性在同一類及其子類之間共用,修改類屬性會影響到同一類及其子類的所有對象」。

聽著挺嚇人,但仔細研究之後,其實倒也不是什麼大不了的事情。

如下代碼:

#!/usr/bin/env pythonclass Bird(object):    name = 'bird'    talent = ['fly']class Chicken(Bird):    passbird = Bird();bird2 = Bird(); # 同類執行個體chicken = Chicken(); # 子類執行個體# 最開始是這樣的print 'Original attr'print id(bird.name),      bird.nameprint id(bird.talent),    bird.talentprint id(bird2.name),     bird2.nameprint id(bird2.talent),   bird2.talentprint id(chicken.name),   chicken.nameprint id(chicken.talent), chicken.talentprint '----------------------------'# 換個名字看看bird.name = 'bird name changed!'print 'after changing name'print id(bird.name),      bird.nameprint id(bird.talent),    bird.talentprint id(bird2.name),     bird2.nameprint id(bird2.talent),   bird2.talentprint id(chicken.name),   chicken.nameprint id(chicken.talent), chicken.talentprint '----------------------------'# 洗個天賦試試(修改類屬性中的元素)bird.talent[0] = 'walk'print 'after changing talent(a list)'print id(bird.name),      bird.nameprint id(bird.talent),    bird.talentprint id(bird2.name),     bird2.nameprint id(bird2.talent),   bird2.talentprint id(chicken.name),   chicken.nameprint id(chicken.talent), chicken.talentprint '----------------------------'# 換個新天賦樹(整個類屬性全換掉)bird.talent = ['swim']print 'after reassign talent'print id(bird.name),      bird.nameprint id(bird.talent),    bird.talentprint id(bird2.name),     bird2.nameprint id(bird2.talent),   bird2.talentprint id(chicken.name),   chicken.nameprint id(chicken.talent), chicken.talentprint '----------------------------'# 洗掉新天賦樹(對新來的類屬性中的元素進行修改)bird.talent[0] = 'dance'print 'changing element after reassigning talent'print id(bird.name),      bird.nameprint id(bird.talent),    bird.talentprint id(bird2.name),     bird2.nameprint id(bird2.talent),   bird2.talentprint id(chicken.name),   chicken.nameprint id(chicken.talent), chicken.talentprint '----------------------------'

運行結果:

PastgiftMacbookPro:python pastgift$ ./changeAttributeTest.py Original attr4301998000 bird4301857352 ['fly']4301998000 bird4301857352 ['fly']4301998000 bird4301857352 ['fly']----------------------------after changing name4301986984 bird name changed!4301857352 ['fly']4301998000 bird4301857352 ['fly']4301998000 bird4301857352 ['fly']----------------------------after changing talent(a list)4301986984 bird name changed!4301857352 ['walk']4301998000 bird4301857352 ['walk']4301998000 bird4301857352 ['walk']----------------------------after reassign talent4301986984 bird name changed!4301859512 ['swim']4301998000 bird4301857352 ['walk']4301998000 bird4301857352 ['walk']----------------------------changing element after reassigning talent4301986984 bird name changed!4301859512 ['dance']4301998000 bird4301857352 ['walk']4301998000 bird4301857352 ['walk']----------------------------

在「Origin」的時候,同類對象,子類對象的相同類屬性的地址都是相同的——這就是所謂的「共用」。

修改name 之後,只有被修改的對象name 屬性發生變化。這是因為對name的賦值操作實際上就是換了一個字串,重新引用。字串本身並沒有發生變化。所以並沒有在同類和子類之間產生互相影響。

接下來,修改talent 中的元素。這時,情況有所改變:同類及其子類的talent 屬性都一起跟著變了——這很好理解,因為它們都引用的記憶體位址都一樣,引用的是同一個對象。

再接下來,給talent 重新賦值,也就是改成引用另外一個對象。結果是只有本執行個體的talent 屬性變化了。從記憶體位址可以看出,本執行個體和其他執行個體的talent 屬性已經不再指向相同的對象了。就是說「至此,本執行個體已經是圈外人士了」。

那麼,最後再次修改talent 中元素後,對其他執行個體無影響的結果也是很好理解了。因為已經是「圈外人士」了嘛,我再怎麼折騰也都是自己的事情了。

所以,「類屬性在同類及其子類之間互相影響」必須有一個前提條件:執行個體建立後,其類屬性從來沒有被重新賦值過,即類屬性依然指向最初所指向的記憶體位址。

最後提一下對象屬性

如下代碼:

   #!/usr/bin/env pythonclass Bird(object):    def __init__(self):        self.talent = ['fly']bird = Bird()bird2 = Bird()# 剛開始的情形print 'Origin'print id(bird.talent), bird.talentprint id(bird2.talent), bird2.talentprint '--------------------'# 修改其中一個對象的屬性bird.talent[0] = 'walk'print 'after changing attribute'print id(bird.talent), bird.talentprint id(bird2.talent), bird2.talentprint '--------------------'# 作死:兩個對象的屬性指向同一個記憶體位址,再修改bird.talent = bird2.talentbird.talent[0] = 'swim'print 'assign to another attribute and change it'print id(bird.talent), bird.talentprint id(bird2.talent), bird2.talentprint '--------------------'運行結果:PastgiftMacbookPro:python pastgift$ ./changeAttributeTest2.py Origin4299867632 ['fly']4299760200 ['fly']--------------------after changing attribute4299867632 ['walk']4299760200 ['fly']--------------------assign to another attribute and change it4299760200 ['swim']4299760200 ['swim']--------------------

由於對象屬性就算內容完全一樣(剛初始化後的屬性內容一般都是一樣的),也會分配到完全不同的記憶體位址上去。所以不存在「同類對象之間影響」的情況。

但如果讓一個對象的屬性和另一個對象的屬性指向同一個地址,兩者之間(但也僅限兩者之間)便又互相牽連起來。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.