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