Python学习之共享引用
Python 學(xué)習(xí)之共享引用
文章目錄
- Python 學(xué)習(xí)之共享引用
- 什么是共享引用
- 共享引用和在原處修改(Shared References and In-Place Changes)
- 共享引用和相等
- 參考資料
什么是共享引用
假設(shè)我們?cè)赑ython交互模式下輸入以下語(yǔ)句:
>>> a = 3 >>> b = a實(shí)際的效果就是變量a和b都引用了相同的對(duì)象(指向了相同的內(nèi)存空間)。這在Python中叫做共享引用——多個(gè)變量名引用了同一個(gè)對(duì)象。
如果再來(lái)一條語(yǔ)句
>>> a = 'spam'會(huì)怎么樣?
變量a引用了由常量表達(dá)式‘spam’所創(chuàng)建的新對(duì)象,但是變量b仍然引用原始的對(duì)象3,因?yàn)檫@個(gè)賦值運(yùn)算改變的不是對(duì)象3,它僅僅改變了變量a的指向,變量b并沒(méi)有發(fā)生改變。
在Python中,變量總是一個(gè)指向?qū)ο蟮闹羔?#xff0c;而不是可改變的內(nèi)存區(qū)域的標(biāo)簽(比如C語(yǔ)言中的變量)。給一個(gè)變量賦一個(gè)新值,并不是修改了原始的對(duì)象,而是讓這個(gè)變量去引用完全不同的一個(gè)對(duì)象。
注意:當(dāng)可變的對(duì)象以及原處的改變進(jìn)入這個(gè)場(chǎng)景,上述情形會(huì)有某種改變。
共享引用和在原處修改(Shared References and In-Place Changes)
有一些對(duì)象和操作確實(shí)會(huì)在原處改變對(duì)象。例如,在一個(gè)列表中通過(guò)偏移進(jìn)行賦值,這確實(shí)會(huì)改變這個(gè)列表對(duì)象,而不是生成一個(gè)新的列表對(duì)象。對(duì)于支持這種在原處修改的對(duì)象,共享引用的時(shí)候一定要小心,因?yàn)閷?duì)一個(gè)變量的修改會(huì)影響其他變量。
請(qǐng)看下面的語(yǔ)句:
>>> L1 = [2, 3, 4] >>> L2 = L1L1 是一個(gè)包含了對(duì)象2、3、4的列表。列表中的元素是通過(guò)他們的位置進(jìn)行讀取的,所以L1[0]引用對(duì)象2. 當(dāng)然,列表自身也是對(duì)象,就像整數(shù)和字符串一樣。在運(yùn)行了上面兩行語(yǔ)句后,L1和L2引用了相同的對(duì)象。
現(xiàn)在加上第3行:
>>> L1 = [2, 3, 4] >>> L2 = L1 >>> L1[0] = 24我們看一下L1和L2的值:
>>> L1 [24, 3 ,4] >>> L2 [24, 3 ,4]在這里,沒(méi)有改變L1,改變了L1所引用的對(duì)象的一個(gè)元素,這類修改會(huì)覆蓋列表對(duì)象中的某部分。因?yàn)檫@個(gè)列表對(duì)象同時(shí)被L1和L2引用,所以在原處修改不僅僅會(huì)影響L1,也會(huì)影響L2。雖然我們沒(méi)有改變L2,但是它的值將發(fā)生變化。
如果你不想要這樣的結(jié)果,那么需要拷貝對(duì)象,而不是創(chuàng)建引用。有很多拷貝列表的辦法,最簡(jiǎn)單的辦法是從頭到尾的切片。
>>> L1 = [2, 3, 4] >>> L2 = L1[:] >>> L1[0] = 24 >>> L1 [24, 3, 4] >>> L2 [2, 3, 4]這里,對(duì)L1的修改不會(huì)影響L2,因?yàn)長(zhǎng)2引用的是L1所引用對(duì)象的一個(gè)拷貝。也就是說(shuō),L1和L2指向了不同的內(nèi)存區(qū)域。
共享引用和相等
>>> x = 42 >>> x = 'shrubbery'因?yàn)镻ython緩存并復(fù)用了小的整數(shù)和小的字符串,執(zhí)行完這兩行代碼后,對(duì)象42也許不會(huì)被回收;相反地,它可能仍被保存在一個(gè)系統(tǒng)表中,等待下一次你的代碼生成另一個(gè)42來(lái)重復(fù)利用。盡管這樣,大多數(shù)種類的對(duì)象都會(huì)在不被引用的時(shí)候馬上回收。
在Python中有2種不同的方法去檢查兩個(gè)變量是否相等。
>>> L = [1, 2, 3] >>> M = L # M and L reference the same object >>> L == M # Same values True >>> L is M # Same objects True==操作符測(cè)試兩個(gè)被引用的對(duì)象是否有相同的值,這種方法往往在Python中用作相等的檢查。
is操作符用來(lái)檢查對(duì)象的同一性。如果兩個(gè)變量名都指向同一個(gè)對(duì)象,則會(huì)返回 True,所以這是一種更嚴(yán)格的相等測(cè)試。
實(shí)際上,is只是比較實(shí)現(xiàn)引用的指針,所以這是一種檢測(cè)共享引用的方法。如果變量名指向不同的對(duì)象,就算這兩個(gè)對(duì)象的值相等,也會(huì)返回 False.
例如:
>>> L = [1, 2, 3] >>> M = [1, 2, 3] # M and L reference different objects >>> L == M # Same values True >>> L is M # Different objects False如果對(duì)小的數(shù)字進(jìn)行類似測(cè)試:
>>> X = 42 >>> Y = 42 # Should be two different objects >>> X == Y True >>> X is Y # Same object anyhow: caching at work! True按理來(lái)說(shuō),第3~4行是可以理解的,因?yàn)閮蓚€(gè)對(duì)象的值一樣;但是第5~6行就讓人匪夷所思了,X引用的42和Y引用的42本來(lái)是2個(gè)對(duì)象,應(yīng)該輸出False才對(duì),不過(guò),因?yàn)樾〉恼麛?shù)和字符串被緩存并復(fù)用了,所以is告訴我們X和Y引用了同一個(gè)對(duì)象。
實(shí)際上,你可以用sys模塊中的getrefcount函數(shù)查詢對(duì)象的被引用次數(shù)。例如,我們查一下整數(shù)1被引用的次數(shù):
>>> import sys >>> sys.getrefcount(1) 812這種對(duì)象緩存和復(fù)用的機(jī)制與代碼是沒(méi)有關(guān)系的。Python這樣做是為了提高執(zhí)行速度。
【End】
參考資料
《Python學(xué)習(xí)手冊(cè)(第4版)》,機(jī)械工業(yè)出版社
總結(jié)
以上是生活随笔為你收集整理的Python学习之共享引用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Python学习之变量、对象和引用
- 下一篇: 编写一个程序,找到大于平均值的项的数目