在python學(xué)習(xí)中引用和對(duì)象是必須要掌握的重要知識(shí)點(diǎn),今天和大家分享的就是這兩部分內(nèi)容,幫助大家快速掌握引用和對(duì)象相關(guān)操作。
python中變量名和對(duì)象是分離的
例子 1:
a = 1
這是一個(gè)簡(jiǎn)單的賦值語(yǔ)句,整數(shù) 1 為一個(gè)對(duì)象,a 是一個(gè)引用,利用賦值語(yǔ)句,引用a指向了對(duì)象1.
例子 2:
>>> a = 1
>>> id(a)
24834392
>>> a = 'banana'
>>> id(a)
139990659655312
第一個(gè)語(yǔ)句中, 2是儲(chǔ)存在內(nèi)存中的一個(gè)整數(shù)對(duì)象,通過(guò)賦值 引用a 指向了 對(duì)象 1
第二個(gè)語(yǔ)句中,內(nèi)存中建立了一個(gè)字符串對(duì)象‘banana’,通過(guò)賦值 將 引用a 指向了 ‘banana’,同時(shí),對(duì)象1不在有引用指向它,它會(huì)被python的內(nèi)存處理機(jī)制給當(dāng)我垃圾回收,釋放內(nèi)存。
例子 3:
>>> a = 3
>>> b = 3
>>> id(a)
10289448
>>> id(b)
10289448
在這里可以看到 這倆個(gè)引用 指向了同一個(gè) 對(duì)象,這是為什么呢? 這個(gè)跟python的內(nèi)存機(jī)制有關(guān)系,因?yàn)閷?duì)于語(yǔ)言來(lái)說(shuō),頻繁的進(jìn)行對(duì)象的銷(xiāo)毀和建立,特別浪費(fèi)性能。所以在Python中,整數(shù)和短小的字符,Python都會(huì)緩存這些對(duì)象,以便重復(fù)使用。
例子 4:
>>> a = 4
>>> b = a
>>> id(a)
36151568
>>> id(b)
36151568
>>> 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ú)立,互不影響。
例子 5:
>>> L1 = [1,2,3]
>>> L2 = L1
>>> id(L1)
139643051219496
>>> id(L2)
139643051219496
>>> 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 的引用沒(méi)有發(fā)生任何變化,但是 列表對(duì)象[1,2,3] 的值 變成了 [10,2,3](列表對(duì)象改變了)
在該情況下,我們不再對(duì)L1這一引用賦值,而是對(duì)L1所指向的表的元素賦值。結(jié)果是,L2也同時(shí)發(fā)生變化。
原因何在呢?因?yàn)?/span>L1,L2的指向沒(méi)有發(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ì)象的引用都受到影響。
?。ㄅc之形成對(duì)比的是,我們之前的賦值操作都沒(méi)有對(duì)對(duì)象自身發(fā)生作用,只是改變引用指向。)
列表可以通過(guò)引用其元素,改變對(duì)象自身(in-place change)。這種對(duì)象類(lèi)型,稱(chēng)為可變數(shù)據(jù)對(duì)象(mutable object),詞典也是這樣的數(shù)據(jù)類(lèi)型。
而像之前的數(shù)字和字符串,不能改變對(duì)象本身,只能改變引用的指向,稱(chēng)為不可變數(shù)據(jù)對(duì)象(immutable object)。
我們之前學(xué)的元組(tuple),盡管可以調(diào)用引用元素,但不可以賦值,因此不能改變對(duì)象自身,所以也算是immutable object.
例子 6:
l = [1,2,3]
for item in l:
item = 8
# 這里只是讓item指向l[i]所指向的對(duì)象,item = 8,則item指向新的對(duì)象8,不改變l[i]
print(l) # [1,2,3]
for i in range(len(l)):
l[i] = 8
# 這里令l[i]指向新的對(duì)象 8
print(l) # [8,8,8]
例子 7:
l2 = []
b = [1,2,3]
for i in range(1,5):
b[1] = i
l2.append(copy.copy(b))
# l2.append(copy.deepcopy(b)) 和copy.copy()結(jié)果一樣
print(l2) # [[1, 1, 3], [1, 2, 3], [1, 3, 3], [1, 4, 3]]
copy.copy() 淺拷貝。只拷貝父對(duì)象,不會(huì)拷貝對(duì)象的內(nèi)部的子對(duì)象。
那么,copy.copy()和copy.deepcopy()有什么區(qū)別呢?
l2 = []
b = [1,[4,5],3]
for i in range(1,5):
b[1][0] = i
l2.append(copy.copy(b)) # [[1, [4, 5], 3], [1, [4, 5], 3], [1, [4, 5], 3], [1, [4, 5], 3]]
# l2.append(copy.deepcopy(b)) # [[1, [1, 5], 3], [1, [2, 5], 3], [1, [3, 5], 3], [1, [4, 5], 3]]
print(l2)
例子 8:
函數(shù)的參數(shù)傳遞探究
def testPara(aList):
aList[0] = 8
print("inside function",aList) # [8, 2, 3]
if __name__ == '__main__':
l1 = [1,2,3]
testPara(l1)
print(l1) # [8, 2, 3]
def testPara(aList):
aList = [1,2]
print("inside function",aList) # [1,2] aList重新指向一個(gè)新的對(duì)象
if __name__ == '__main__':
l1 = [1,2,3]
testPara(l1)
print(l1) # [1, 2, 3]
這里要想直接把l1在函數(shù)內(nèi)改變,可以在函數(shù)return l1
def test(l:list):
l.pop(0)
if __name__ == '__main__':
l = [1,2,3]
test(l)
print(l) # [2,3]
來(lái)源:推酷