python的一切變量都是對象,變量的存儲采用了引用語義的方式,存儲的只是一個變量的值所在的內(nèi)存地址,而不是這個變量的本身。
基于內(nèi)存地址的分類
Python中的數(shù)據(jù)類型基于內(nèi)存地址分類可以分為:
可變類型: 列表,字典,集合
不可變類型:數(shù)字,字符串,元組
這里的可變不可變,是指當該數(shù)據(jù)類型的對應(yīng)變量的值發(fā)生了改變,那么它對應(yīng)的內(nèi)存地址是否發(fā)生改變
![]() 可變類型
|
![]() 不可變類型
|
|---|
-
對于不可變類型
變量的每一次初始化,都開辟了一個新的內(nèi)存空間,同時將新內(nèi)容的地址賦值給變量。
要注意的是,即使變量對應(yīng)的地址發(fā)生改變,但舊地址的內(nèi)容其實并沒有被修改,仍在內(nèi)存中,我們可以通過引入ctypes模塊讀取地址的內(nèi)
-
對于可變類型
當對該數(shù)據(jù)類型中的元素進行一些增刪改操作的時候,不會影響到該變量本身的地址,只會改變其內(nèi)部元素的地址引用。
當然,如果對其重新初始化(賦值)的時候,就給該變量重新賦予了一個新的內(nèi)存地址。
賦值
結(jié)合上面對于可變、不可變數(shù)據(jù)類型的地址存儲及其地址變化的理解,我們再來討論Python中對變量的賦值。
Python中的賦值類似于c++中的引用,本質(zhì)是對變量對象的引用,獲得對方所指向的內(nèi)存地址
-
對于不可變類型
我們對變量的賦值操作,本質(zhì)上只是把等號右邊的值所在的內(nèi)存地址給了左邊的變量
從上圖我們可以看出,a、b均通過賦值得到了“hello world”的內(nèi)存地址之后,即使對a重新賦值,也只是a得到了新建的值的地址,對已賦值的b沒有影響
-
對于可變類型
從上圖我們可以看到a、b均通過賦值得到了一個列表,雖然表面上我們分別對a、b列表的內(nèi)容進行了修改,但實際上修改的卻是內(nèi)存中該列表所指向的內(nèi)部元素,因此,他們的修改會互相影響(他們本就共用的同一個列表)
淺拷貝
淺拷貝可用copy模塊中的copy函數(shù),進行淺拷貝時,只會拷貝該變量元素的地址(可以理解為只拷貝了第一層)。

我們可以看到,淺拷貝只是新建了一塊內(nèi)存,用于將列表a中的各元素地址拷貝了出來,b得到的是一個新的內(nèi)存地址,只不過b所指向的內(nèi)存中各元素地址和a中的相同。
因此,如果元素是不可變類型,則修改只會改變各自的地址,互相之間沒有影響,但如果某個元素是可變類型,則對其內(nèi)容的修改并不會改變這個元素本身的地址,就會互相影響到。
深拷貝
淺拷貝可用copy模塊中的deepcopy函數(shù),深拷貝會完全復(fù)制原變量相關(guān)的所有數(shù)據(jù),在內(nèi)存中生成一套完全一樣的內(nèi)容,在這個過程中我們對這兩個變量中的一個進行任意修改都不會影響其他變量。







