變量在我們的編程中是最基礎的概念,它就相當于我們蓋大樓用的磚塊一樣不可或缺。理解變量的運行方式至關重要。

九層之臺,始于壘土;合抱之木,始于毫末;千里之行,始于足下!

今天就讓我們一起來談一談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:食用人數:1123456:食用人數: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]

總結:

可變對象:變量所指向的內存地址處的值是可以被改變的

不可變對象:變量所指向的內存地址處的值是不可以被改變。

創作不易,且讀且珍惜。如有錯漏還請海涵并聯系作者修改,內容有參考,如有侵權,請聯系作者刪除。如果文章對您有幫助,還請動動小手,您的支持是我最大的動力。

關注小編公眾號:偷偷學習,卷死他們