變量在我們的編程中是最基礎(chǔ)的概念,它就相當(dāng)于我們蓋大樓用的磚塊一樣不可或缺。理解變量的運(yùn)行方式至關(guān)重要。
九層之臺(tái),始于壘土;合抱之木,始于毫末;千里之行,始于足下!
今天就讓我們一起來(lái)談一談Python變量的那些事。
1. 變量不是盒子
讓我們看看下面的代碼
a = "hello,world"b = ac = [1,2,3]
對(duì)于我們初學(xué)者來(lái)說(shuō),變量的賦值是最容易走進(jìn)誤區(qū)的地方。最常見(jiàn)的誤區(qū)是什么呢?
定義一個(gè)變量,就在內(nèi)存中創(chuàng)建一個(gè)變量盒子,然后把變量的值放在這個(gè)盒子中
讓我們看看下面這張圖,這種想法是大錯(cuò)特錯(cuò)的。就是因?yàn)檫@種誤區(qū),使得我們的代碼可能遇到很多問(wèn)題。
那正確的是什么?變量賦值的時(shí)候做了什么呢?
2. 千奇百怪的變量
a = "hello,world"b = ac = [1,2,3]
所以上面的代碼究竟做了什么?在這之前,我先大家講個(gè)故事。
上個(gè)世紀(jì)90年代的時(shí)候,我們大名鼎鼎的蟒蛇自助大酒樓開(kāi)業(yè)了。顧名思義,這家酒樓主要是做自助餐的,但是呢?它每個(gè)顧客只能吃一種美食,并且會(huì)把美食分布在不同的房間里面,美食種類是不固定的,顧客有什么需求就提供什么。
這天,我們的小a同學(xué)來(lái)到了酒樓,跟前臺(tái)說(shuō),我要吃“hello,world”,于是,酒店前臺(tái)就新開(kāi)了一間房間,房號(hào)為:00010,并且在里面放上了我們的“hello,world”,并且給了 a 一張通行證,這張通行證只能通往00010號(hào)房間。并且記錄下
hello,world:食用人數(shù):1
,當(dāng)a想吃的時(shí)候,就自己拿通行證去00010號(hào)房間去拿過(guò)不久,小b也來(lái)到了我們的酒店,跟酒店前臺(tái)說(shuō),我要跟a吃一樣的東西。于是酒店前臺(tái),也給了b一張通行證,b根據(jù)通行證也能去到00010號(hào)房間去拿hello,world。酒店前臺(tái)再次記錄:
hello,world:食用人數(shù):2
緊接著,我們小c同學(xué)也來(lái)了,他跟b不一樣,他有自己想吃的食物。他跟酒店前臺(tái)說(shuō):我要吃[1,2,3]。顧客有了新的需求,酒店前臺(tái)就又新開(kāi)一件房間,房號(hào)為:00020,并且也在里面放上了[1,2,3]。同樣給c一張通行證。然后記錄下:
[1,2,3]:食用人數(shù):1
我們可以帶著這個(gè)故事往下面看
根據(jù)這張圖,我們上面的故事中:
- 顧客a、b、c:變量a、b、c
- 酒店:內(nèi)存空間
- 酒店前臺(tái):Python解釋器
- 房間:為對(duì)象劃分的內(nèi)存空間
- 房間號(hào):對(duì)象所在的內(nèi)存地址
- 食物:各種各樣的對(duì)象(字符串、列表、字典、數(shù)字。。。)
- 前臺(tái)記錄的食用人數(shù):引用計(jì)數(shù)
- 通信證號(hào)碼:變量引用的內(nèi)存地址
實(shí)際上當(dāng)我們對(duì)一個(gè)變量賦值的時(shí)候,我們的變量并沒(méi)有存儲(chǔ)這個(gè)值。而是綁定了一個(gè)內(nèi)存地址id,當(dāng)我們要用這個(gè)變量的值的時(shí)候,就去內(nèi)存中尋找這個(gè)地址的存儲(chǔ)的值
接著上面的故事,我們的小a同學(xué),吃膩了hello,world,現(xiàn)在想吃123456,于是跑去跟酒店前臺(tái)說(shuō),我現(xiàn)在想吃123456了,酒店前臺(tái)二話不說(shuō),新開(kāi)了一間房間,房號(hào)為00030,里面放著123456,并且更新了a同學(xué)的通行證,此時(shí)這張通信證只能去00030號(hào)房吃123456。前臺(tái)繼續(xù)記錄
hello,world:食用人數(shù):1
、123456:食用人數(shù):1
在代碼中,我們改變了a變量的值,會(huì)發(fā)生什么呢?
我們?cè)倏纯?,改變a的變量會(huì)發(fā)生什么?
a = 123456
會(huì)這樣嗎?
我們改變a的值的時(shí)候,并不會(huì)直接去改變a指向的內(nèi)存地址存儲(chǔ)的值,而是新開(kāi)辟一個(gè)空間存放新的值123456,把a(bǔ)的指向改成新空間的地址00030,如下圖所示。正確的應(yīng)該是這樣:
我們的b同學(xué)非常喜歡模仿,她現(xiàn)在又不想吃hello,world了。于是他就跑下樓去跟酒店前臺(tái)說(shuō):我要吃[1,2,3]。注意哦,這次b同學(xué)說(shuō)的是,我要吃[1,2,3],而不是說(shuō)我要吃跟c一樣的。雖然他們的食物是一樣的。但是我們的前臺(tái)并不會(huì)直接給b 00020號(hào)房間的通行證。而是新開(kāi)一間房間,房間號(hào)00040,里面放[1,2,3],并且給b一張通行證指向00040號(hào)房間。同事記錄上
(00040)[1,2,3]:食用人數(shù):1
、(00010)hello,world:食用人數(shù):0
b = [1,2,3]
為什么呢?其實(shí)這里很好理解,因?yàn)槲覀僢賦值的時(shí)候是新建了一個(gè)對(duì)象。只要新建對(duì)象,就會(huì)重新開(kāi)辟空間。
但是,像這樣
b = c
這樣并沒(méi)有新建對(duì)象,而是將c的引用傳遞給了b,他們都指向一個(gè)對(duì)象。這里小伙伴們留意一下,不要被我的例子給帶跑偏了。
這個(gè)時(shí)候,我們的酒店前臺(tái)發(fā)現(xiàn)00010號(hào)房間里面的hello,world已經(jīng)沒(méi)人吃了。這個(gè)時(shí)候酒店前臺(tái)就會(huì)把這間房間收回來(lái),并且把里面的hello,world食物丟掉。這個(gè)就是python的垃圾回收機(jī)制。
此時(shí),又來(lái)了以為同學(xué)d,d跟酒店前臺(tái)說(shuō),我要跟c吃一樣的,酒店前臺(tái)就給d發(fā)了一張通行證,d根據(jù)通行證能去到00020號(hào)房間去拿[1,2,3]。酒店前臺(tái)再次記錄:
[1,2,3]:食用人數(shù):2
d = c
但是我們的d同學(xué)非常挑剔,他不滿足現(xiàn)有的[1,2,3],他想要加點(diǎn)菜,也是就跟前臺(tái)說(shuō)要加菜:這時(shí)候00020房間里面放的東西就變成了[1,2,3,4]
d.append(4)
此時(shí),我們發(fā)現(xiàn)了一個(gè)問(wèn)題,c同學(xué)什么也沒(méi)有干,但是他能吃的食物從[1,2,3]變成了[1,2,3,4]
這究竟是什么問(wèn)題呢?
為什么我們之前a從“hello,world”變成123456的時(shí)候,是新開(kāi)辟一塊空間。但是現(xiàn)在d從[1,2,3]變成[1,2,3,4],卻直接在原內(nèi)存空間里修改呢?
這就是python經(jīng)典的面試題:對(duì)象的可變性?什么是可變對(duì)象,什么是不可變對(duì)象?
3. 可變對(duì)象與不可變對(duì)象
在python中,一切皆對(duì)象,但是這對(duì)象也分為兩類:
- 可變對(duì)象(3個(gè)):List(列表)、Dictionary(字典)、Set(集合)
- 不可變對(duì)象(3個(gè)):Number(數(shù)字)、String(字符串)、Tuple(元組)
Python中看可變與不可變數(shù)據(jù)類型,主要是看變量所指向的內(nèi)存地址處的值是否會(huì)改變 。
3.2 不可變對(duì)象
>>> a = 10000>>> id(a)139964684838128>>> a = 30000 # 不可變對(duì)象,改變變量的值,實(shí)際上是實(shí)例化新對(duì)象、開(kāi)辟新內(nèi)存空間>>> id(a) # 產(chǎn)生了新的內(nèi)存地址,說(shuō)明已經(jīng)不是原來(lái)的對(duì)象了139964684837872>>>
3.3 可變對(duì)象
>>> a = [1,2,3]>>> b = a>>> id(a)139711046464264>>> id(b)139711046464264>>> b.append(4) # 可變對(duì)象,允許在原地改變對(duì)象的值>>> id(b)139711046464264 # 內(nèi)存地址沒(méi)有改變,說(shuō)明是在原內(nèi)存空間改變值>>> id(a)139711046464264>>> b[1, 2, 3, 4]>>> a[1, 2, 3, 4]
總結(jié):
可變對(duì)象:變量所指向的內(nèi)存地址處的值是可以被改變的
不可變對(duì)象:變量所指向的內(nèi)存地址處的值是不可以被改變。
創(chuàng)作不易,且讀且珍惜。如有錯(cuò)漏還請(qǐng)海涵并聯(lián)系作者修改,內(nèi)容有參考,如有侵權(quán),請(qǐng)聯(lián)系作者刪除。如果文章對(duì)您有幫助,還請(qǐng)動(dòng)動(dòng)小手,您的支持是我最大的動(dòng)力。
關(guān)注小編公眾號(hào):偷偷學(xué)習(xí),卷死他們