目錄
前言:c++不同於python的顯著特點,就是有指標和引用,這讓我們在呼叫引數的時候更加清晰明朗。但python中沒有指標和引用的概念,導致很多時候引數的傳遞和呼叫的時候會產生疑問:我到底是複製了乙份新的做操作還是在它指向的記憶體操作?
這個問題根本上和可變、不可變變數有關,我想把這個二者的區別和聯絡做乙個總結,以更深入地理解python內部的操作。我本身非科班出身,如有不當之處敬請批評指正。
在了解可變、不可變變數的基本定義之前,我們需要明白變數是如何被建立的。
x = 1
python直譯器會判斷1在記憶體中是否存在,若不存在,python會分配記憶體,在記憶體中建立數字1,然後看變數x是否存在,若不存在就建立x,最後把1賦值給x。
y = 1
當繼續輸入上行**時,1已經在記憶體中被建立了,現在是否需要重新建立乙個1,然後賦值給y呢?還是直接將剛才就建立好的1賦值給y呢?答案是後者。我們可以通過id或者is來判斷是否在記憶體中是同乙個位址。
print(id(x) == id(y))
# or
print(x is y)
但當我們換成乙個列表來嘗試呢?
a = [1,2,3]
b = [1,2,3]
print(id(a) == id(b))
答案卻和上面的結果相反,也就是說記憶體中即使有了x的[1,2,3],python中www.cppcns.com要建立把[1,2,3]賦給y的時候並沒有把x指向的那個賦過去,而是重新在記憶體中開闢了一塊新的空間,建立了乙個新的[1,2,3]!這就引出了可變和不可變變數。
字面意思
按照我的個人理解,可變變數(mutable variable)就是記憶體中內容可以被修改的變數,而不可變變數(immutable variable)就是記憶體中內容不可以被修改的變數。
聽起來比較抽象。我們可以把變數名理解為乙個指標或者引用,他們都指向了記憶體中的一塊空間。比如上節中x和y同時指向了1的那塊空間,a指向了[1,2,3]的那部分。那麼如何理解記憶體中的內bcbmh容可以被修改呢?對於乙個int型的變數,我建立了1,那麼這之後*任何在這個作用域中所有被賦為1 的變數都會指向它,而外部沒有方法來把這個記憶體中的內容改成2或者其他值*。而對於列表來說,那塊[1,2,3]我隨時可以把他改為[1,2,3,4],這就是記憶體中內容可以被修改。
所有的變數都可以按可變、不可變變數來分類,那麼我將常用的一些變數型別進行分類。
copy和deepcopy都表示拷貝,那麼二者的區別就在於可變、不可變物件。copy和deepcopy對於不可變物件來說是沒有區別的,都是把指向記憶體已有的空間的引用進行拷貝;但對於可變物件,copy是拷貝指向記憶體已有空間的引用,而deepcopy才是新開闢一塊空間,將原來的內容完全拷貝,然後返回新的空間的引用。
引數傳遞的過程也是很容易出現疑惑的過程。c++中的引數傳遞很明確,引用就是引用,形參就是形參,但python中不是,因為p程式設計客棧ython中沒有明確的指標、引用。
對不可變變數,傳遞進函式後由於作用域改變,函式內部有新的bcbmh空間,因此會產生形參,將原來的不可變變數進行複製,然後在函式內部進行後續操作。
對可變變數,本身內容就可以被修改,那麼在函式內部也允許修改本身,因此傳遞進函式的是該記憶體空間的引用,對該引數操作,相應的在主函式也會被修改。
python中可變變數和不可變變數的區別
可變 位址不變,裡面的內容改變 list dict set 經典案例 list1 1,3,5,8,9,0 list2 list1 list1.remove 5 print list2 結果 1,3,5,8,9,0 str1 abc str2 str1 str1 abcd print str2 結果 ...
Python中不可變與可變
在python的資料型別中,有用可變和不可變的兩種型別,那下面就來看一看兩種資料型別有什麼區別 old var hello print old var hello new var old var new var world print old var hello world 這符合我們的邏輯嗎?是不...
python可變與不可變
可變與不可變型別的實質實際上就是儲存機制的不同 不可變型別 比如字串 被稱為不可變的字串行,每個字元底層均有規範的unicode碼對應,記憶體規定無法對單一的乙個字元進行修改,要修改字串必須重新指向乙個全新的字串 可變型別 一方面,該列表可以保證在位址不變的前提下,改變列表內容 另一方面,該引用也可...