python中的引用怎么理解_python 引用和对象理解
今天瀏覽博客的時(shí)候看到這么一句話: python中變量名和對(duì)象是分離的;最開始的時(shí)候是看到這句話的時(shí)候沒有反應(yīng)過來。決定具體搞清楚一下python中變量與對(duì)象之間的細(xì)節(jié)。(其實(shí)我感覺應(yīng)該說 引用和對(duì)象分離 更為貼切)
從最開始的變量開始思考:
在python中,如果要使用一個(gè)變量,不需要提前進(jìn)行聲明,只需要在用的時(shí)候,給這個(gè)變量賦值即可 (這個(gè)和C語言等靜態(tài)類型語言不同,和python為動(dòng)態(tài)類型有關(guān))。
舉第一個(gè)栗子:
a = 1
這是一個(gè)簡(jiǎn)單的賦值語句,整數(shù) 1 為一個(gè)對(duì)象,a 是一個(gè)引用,利用賦值語句,引用a指向了對(duì)象1;這邊形象比喻一下:這個(gè)過程就相當(dāng)于“放風(fēng)箏”,變量a就是你手里面的“線”,python就跟那根“線”一樣,通過引用來接觸和拴住天空中的風(fēng)箏——對(duì)象。
你可以通過python的內(nèi)置函數(shù) id() 來查看對(duì)象的身份(identity),這個(gè)所謂的身份其實(shí)就是 對(duì)象 的內(nèi)存地址:
注:
python一切皆對(duì)象的理念,所以函數(shù)也是一個(gè)對(duì)象,因此可以使用 id() 函數(shù)的__doc__方法來查看這個(gè)函數(shù)的具體描述:
>>> id.__doc__
"id(object) -> integer\n\nReturn the identity of an object. This is guaranteed to be unique among\nsimultaneously existing objects. (Hint: it's the object's memory address.)"
第二個(gè)栗子:
a = 2
a = 'banana'
利用上面第一個(gè)栗子用到的 id()函數(shù):
>>> a = 1
>>> id(a)
24834392
>>> a = 'banana'
>>> id(a)
139990659655312
第一個(gè)語句中, 2是儲(chǔ)存在內(nèi)存中的一個(gè)整數(shù)對(duì)象,通過賦值 引用a 指向了 對(duì)象 1
第二個(gè)語句中,內(nèi)存中建立了一個(gè)字符串對(duì)象‘banana’,通過賦值 將 引用a 指向了 ‘banana’,同時(shí),對(duì)象1不在有引用指向它,它會(huì)被python的內(nèi)存處理機(jī)制給當(dāng)我垃圾回收,釋放內(nèi)存。
第三個(gè)栗子:
a = 3
b = 3
通過函數(shù)查看 變量a 和 變量b的引用情況:
>>> a = 3
>>> b = 3
>>> id(a)
10289448
>>> id(b)
10289448
在這里可以看到 這倆個(gè)引用 指向了同一個(gè) 對(duì)象,這是為什么呢? 這個(gè)跟python的內(nèi)存機(jī)制有關(guān)系,因?yàn)閷?duì)于語言來說,頻繁的進(jìn)行對(duì)象的銷毀和建立,特別浪費(fèi)性能。所以在Python中,整數(shù)和短小的字符,Python都會(huì)緩存這些對(duì)象,以便重復(fù)使用。
第四個(gè)栗子:
1. a = 4
2. b = a(這里就是讓引用b指向引用a指向的那個(gè)對(duì)象)
3. a = a + 2
通過函數(shù)查看引用情況:
當(dāng)執(zhí)行到第2步的時(shí)候,查看一下 a 和 b 的引用:
>>> a = 4
>>> b = a
>>> id(a)
36151568
>>> id(b)
36151568
可以看到 a 和 b 都指向了 整數(shù)對(duì)象 4
接下來指向第3步:
>>> a = a+2
>>> id(a)
36151520
>>> id(b)
36151568
可以看到 a 的引用改變了,但是 b 的引用未發(fā)生改變;a,b指向不同的對(duì)象; 第3句對(duì) a 進(jìn)行了重新賦值,讓它指向了新的 對(duì)象6;即使是多個(gè)引用指向同一個(gè)對(duì)象,如果一個(gè)引用值發(fā)生變化,那么實(shí)際上是讓這個(gè)引用指向一個(gè)新的引用,并不影響其他的引用的指向。從效果上看,就是各個(gè)引用各自獨(dú)立,互不影響。
第五個(gè)栗子(這個(gè)栗子會(huì)涉及到 python中的 可變數(shù)據(jù)類型 和 不可變數(shù)據(jù)類型):
開始這個(gè)栗子之前,請(qǐng)記得注意到 第四個(gè)栗子的不同之處。
1. L1 = [1, 2, 3]
2. L2 = L1
3. L1[0] = 10
通過函數(shù)查看引用情況:
當(dāng)執(zhí)行第1步 和 第二步 的時(shí)候,查看一下 L1 和 L2 的引用情況:
>>> L1 = [1,2,3]
>>> L2 = L1
>>> id(L1)
139643051219496
>>> id(L2)
139643051219496
此時(shí) L1 和 L2 的引用相同,都是指向 [1,2,3]這個(gè)列表對(duì)象。
接下來,繼續(xù)執(zhí)行第3步:
>>> L1[0] = 10
>>> id(L1)
139643051219496
>>> id(L2)
139643051219496
>>> L2
[10, 2, 3]
同樣的跟第四個(gè)栗子那樣,修改了其中一個(gè)對(duì)象的值,但是可以發(fā)現(xiàn) 結(jié)果 并不與 第四個(gè)栗子那樣, 在本次實(shí)驗(yàn)中,L1 和 L2 的引用沒有發(fā)生任何變化,但是 列表對(duì)象[1,2,3] 的值 變成了 [10,2,3](列表對(duì)象改變了)
在該情況下,我們不再對(duì)L1這一引用賦值,而是對(duì)L1所指向的表的元素賦值。結(jié)果是,L2也同時(shí)發(fā)生變化。
原因何在呢?因?yàn)長(zhǎng)1,L2的指向沒有發(fā)生變化,依然指向那個(gè)表。表實(shí)際上是包含了多個(gè)引用的對(duì)象(每個(gè)引用是一個(gè)元素,比如L1[0],L1[1]..., 每個(gè)引用指向一個(gè)對(duì)象,比如1,2,3), 。而L1[0] = 10這一賦值操作,并不是改變L1的指向,而是對(duì)L1[0], 也就是表對(duì)象的一部份(一個(gè)元素),進(jìn)行操作,所以所有指向該對(duì)象的引用都受到影響。
(與之形成對(duì)比的是,我們之前的賦值操作都沒有對(duì)對(duì)象自身發(fā)生作用,只是改變引用指向。)
列表可以通過引用其元素,改變對(duì)象自身(in-place change)。這種對(duì)象類型,稱為可變數(shù)據(jù)對(duì)象(mutable object),詞典也是這樣的數(shù)據(jù)類型。
而像之前的數(shù)字和字符串,不能改變對(duì)象本身,只能改變引用的指向,稱為不可變數(shù)據(jù)對(duì)象(immutable object)。
我們之前學(xué)的元組(tuple),盡管可以調(diào)用引用元素,但不可以賦值,因此不能改變對(duì)象自身,所以也算是immutable object.
is關(guān)鍵字:
當(dāng)然,我們也可以要想知道是否指向同一個(gè)對(duì)象,我們可以使用 python的 is 關(guān)鍵詞,is用于判斷兩個(gè)引用所指的對(duì)象是否相同。
就像上述第四個(gè)栗子 當(dāng)進(jìn)行到 第1步 和 第2步 的時(shí)候:
>>> a = 4 ……id(a) = 36151568
>>> b =a ……id(b) = 36151568
>>> a is b
True
當(dāng)進(jìn)行到第3步的時(shí)候:
>>> a = a + 2 ……id(a) = 36151520
>>> a is b ……id(b) = 36151568
False
突然想到,對(duì)于python 的 深拷貝 和 淺拷貝 的理解,也是可以根據(jù)這個(gè)進(jìn)行驗(yàn)證,可以通過第五個(gè)栗子進(jìn)行輔助理解。
總結(jié)
以上是生活随笔為你收集整理的python中的引用怎么理解_python 引用和对象理解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网站性能优化--CRP
- 下一篇: 学习File API用于前端读取文件