Python 面試高頻問(wèn)題:可變數(shù)據(jù)類型和不可變數(shù)據(jù)類型的區(qū)別
Python可變數(shù)據(jù)類型和不可變數(shù)據(jù)類型是一個(gè)基礎(chǔ)而且重要的考點(diǎn)。簡(jiǎn)單地說(shuō):這里的可變和不可變是指當(dāng)變量改變的時(shí)候,數(shù)據(jù)的地址是否會(huì)改變!
可變數(shù)據(jù)類型:如果改變了變量的值,相當(dāng)于是新建了一個(gè)對(duì)象(即地址會(huì)被改變)。
可變數(shù)據(jù)類型:變量的值發(fā)生變化,但是對(duì)象的地址不會(huì)改變。
不可變數(shù)據(jù)類型:元組,字符串,數(shù)值。
可變數(shù)據(jù)類型:字典,列表,集合。
引用
在講可變數(shù)據(jù)類型和不可變數(shù)據(jù)類型之前我們要講一下引用的概念。python變量保存的是對(duì)象的引用,這個(gè)引用指向堆內(nèi)存里的對(duì)象,在堆中分配的對(duì)象分為兩類,一類是可變對(duì)象,一類是不可變對(duì)象。例如:s1="abc"。
其實(shí)變量s1 就是對(duì)象 abc的引用,s1指向了存儲(chǔ)abc的內(nèi)存地址,如果想看s1的地址值,可以使用函數(shù)id,id會(huì)把地址值轉(zhuǎn)換成十進(jìn)制。使用print(id(s1))即可,如下圖所示:
不可變數(shù)據(jù)類型
我們以字符串舉例,直接上代碼:
s1="abc"
print(id(s1))
s1="xyz"
print(id(s1))
輸出:
140712532603136
140712532603168
從輸出結(jié)果可見改變字符串類型變量的值,地址也會(huì)隨之變化。
我們接下來(lái)看這個(gè)實(shí)例,也是面試筆試中經(jīng)常出的題目。
#在上面代碼基礎(chǔ)上,編寫如下代碼:
s2=s1
print(id(s1))
print(id(s2))
輸出:
743316570224
743316570224
可以看到s2=s1 實(shí)際上是s2 和s1都指向了同一個(gè)地址。
我們繼續(xù),改變s2的值。
s2="def"
print(id(s1))
print(s1)
print(id(s2))
print(s2)
輸出:
879864758384
xyz
879889887984
def
看到這里,我們就能夠理解為什么改變了s2 的值并沒(méi)有影響s1的值。因?yàn)閟1 和s2指向了不同的地址,所以s1的值并沒(méi)有被改變!
可變數(shù)據(jù)類型
我們以列表舉例:
l = [1, 2, 3]
print(id(l))
l.remove(1) # 刪除元素
print(id(l))
l.append(4) # 增加元素
print(id(l))
l[1] = '8' # 修改元素
print(id(l))
輸出:
405927907912
405927907912
405927907912
405927907912
可以看到對(duì)列表進(jìn)行增刪改操作,列表的地址都沒(méi)有變化,只是改變了變量的值,而不會(huì)新建一個(gè)對(duì)象,變量引用的對(duì)象的地址也不會(huì)變化。
再看下面這個(gè)實(shí)例,與前面的字符串賦值實(shí)例類似。
l1=['a','b','c']
l2=l1
print(id(l1))
print(id(l2))
l2.append('d')
print("************")
print(id(l1))
print(l1)
print(id(l2))
print(l2)
輸出:
838366483528
838366483528
************
838366483528
['a', 'b', 'c', 'd']
838366483528
['a', 'b', 'c', 'd']
輸出結(jié)果這里就不再多做解釋了,因?yàn)?l1 和l2的地址相同,所以彼此間會(huì)產(chǎn)生影響。
list的拷貝
有的同學(xué)可能要問(wèn),如果想讓list 像字符串一樣拷貝并生成同值但是不同地址的兩個(gè)list,該如何操作呢?其實(shí)這個(gè)問(wèn)題的本質(zhì)是list直接賦值(用 = 是直接賦值)和拷貝的區(qū)別(拷貝又分為淺拷貝和深拷貝),我會(huì)再寫一篇文章來(lái)詳細(xì)介紹淺拷貝和深拷貝的相關(guān)知識(shí)點(diǎn),也請(qǐng)大家持續(xù)關(guān)注。
這里先介紹一種比較簡(jiǎn)單的方法進(jìn)行拷貝,使用list()構(gòu)造函數(shù),代碼如下:
l3=['x','y','z']
l4=list(l3)
print(id(l3))
print(id(l4))
l4.append('a')
print(l3)
print(l4)
輸出:
831456302152
831480344136
['x', 'y', 'z']
['x', 'y', 'z', 'a']
從結(jié)果可以看到,l3 和l4的地址不同,所以彼此間不會(huì)發(fā)生影響。我們還可以通過(guò)使用索引,列表生成式,copy()等方式使兩個(gè)列表指向不同的列表對(duì)象,這里就不再一一介紹了!