1. 程式人生 > >詳解Python變數在記憶體中的儲存

詳解Python變數在記憶體中的儲存

這篇文章主要是對python中的資料進行認識,對於很多初學者來講,其實資料的認識是最重要的,也是最容易出錯的。本文結合資料與記憶體形態講解python中的資料,內容包括:

  • 引用與物件
  • 可變資料型別與不可變資料型別
  • 引用傳遞與值傳遞
  • 深拷貝與淺拷貝

id函式:你可以通過python的內建函式 id() 來檢視物件的身份(identity),這個所謂的身份其實就是 物件 的記憶體地址

一、引用與物件:引用與物件的關係: 

 
  1. #建立兩個物件

  2. name1='wupeiqi'

  3. name2='alex'

物件:當建立資料物件時,在記憶體中會儲存物件的值,這個值就是物件自己;(字串物件:”wupeiqi”) 
引用:物件儲存在記憶體空間,外部想要使用物件的值,需要使用引用,就是‘name1’,’name2’。記憶體會儲存物件的引用數量,當某個物件的引用數量為0時,物件會被回收。

二、可變資料型別與不可變資料型別 
1,資料分類:

  • 可變資料型別:列表list和字典dict
  • 不可變資料型別:整型int、浮點型float、字串型string和元組tuple

這裡的可變不可變,是指記憶體中的那塊內容(value)是否可以被改變。如果是不可變型別,在對物件本身操作的時候,必須在記憶體中新申請一塊區域

(因為老區域不可變)。如果是可變型別,對物件操作的時候,不需要再在其他地方申請記憶體,只需要在此物件後面連續申請(+/-)即可,也就是它的address會保持不變,但區域會變長或者變短。

(1)python中的不可變資料型別,不允許變數的值發生變化,如果改變了變數的值,相當於是新建了一個物件,而對於相同的值的物件,在記憶體中則只有一個物件,內部會有一個引用計數來記錄有多少個變數引用這個物件; 
(2)可變資料型別,允許變數的值發生變化,即如果對變數進行append、+=等這種操作後,只是改變了變數的值,而不會新建一個物件,變數引用的物件的地址也不會變化,不過對於相同的值的不同物件,在記憶體中則會存在不同的物件,即每個物件都有自己的地址,相當於記憶體中對於同值的物件儲存了多份,這裡不存在引用計數,是實實在在的物件

。”

2,不可變資料型別:不可變是指物件本身的值是不可變的(當你建立a=1整型物件,用a去引用它,記憶體中的物件1是不變得,當執行a=2時,只是重新建立了物件2,用a引用,如果1物件沒有其他引用會被回收)

 
  1. >>> x = 1

  2. >>> id(x)

  3. 31106520

  4. >>> y = 1

  5. >>> id(y)

  6. 31106520

  7. >>> x = 2

  8. >>> id(x)

  9. 31106508

  10. >>> y = 2

  11. >>> id(y)

  12. 31106508

  13. >>> z = y

  14. >>> id(z)

  15. 31106508

解釋:這裡的不可變大家可以理解為x引用的地址處的值是不能被改變的,也就是31106520地址處的值在沒被垃圾回收之前一直都是1,不能改變,如果要把x賦值為2,那麼只能將x引用的地址從31106520變為31106508,相當於x = 2這個賦值又建立了一個物件,即2這個物件,然後x、y、z都引用了這個物件,所以int這個資料型別是不可變的,如果想對int型別的變數再次賦值,在記憶體中相當於又建立了一個新的物件,而不再是之前的物件。從下圖中就可以看到上面程式的過程。 

3,可變物件:可變是指物件本身的值是可變的list,dict物件的值其實是引用了其他物件,當改變物件的值時,其實是引用了不同的物件)

 
  1. >>> a = [1, 2, 3]

  2. >>> id(a)

  3. 41568816

  4. >>> a = [1, 2, 3]

  5. >>> id(a)

  6. 41575088

  7. >>> a.append(4)

  8. >>> id(a)

  9. 41575088

  10. >>> a += [2]

  11. >>> id(a)

  12. 41575088

  13. >>> a

  14. [1, 2, 3, 4, 2]

解釋:(1)進行兩次a = [1, 2, 3]操作,兩次a引用的地址值是不同的,也就是說其實建立了兩個不同的物件,這一點明顯不同於不可變資料型別,所以對於可變資料型別來說,具有同樣值的物件是不同的物件,即在記憶體中儲存了多個同樣值的物件,地址值不同。 
(2)我們對列表進行新增操作,分別a.append(4)和a += [2],發現這兩個操作使得a引用的物件值變成了上面的最終結果,但是a引用的地址依舊是41575088,也就是說對a進行的操作不會改變a引用的地址值,只是在地址後面又擴充了新的地址,改變了地址裡面存放的值,所以可變資料型別的意思就是說對一個變數進行操作時,其值是可變的,值的變化並不會引起新建物件,即地址是不會變的,只是地址中的內容變化了或者地址得到了擴充。下圖對這一過程進行了圖示,可以很清晰地看到這一過程。 

三、引用傳遞與值傳遞:可變物件為引用傳遞,不可變物件為值傳遞。(函式傳值) 
1,引用傳遞:當傳遞列表或者字典時,如果改變引用的值,就修改了原始的物件。

 
  1. # 添加了一個string型別的元素新增到末尾

  2.  
  3. def ChangeList(lis):

  4. lis.append('hello i am the addone')

  5. print lis

  6. return

  7.  
  8. lis = [1, 2, 3]

  9. ChangeList(lis)

  10. print lis

  11.  
  12. 輸出:

  13. [1,2,3, 'hello i am the addone']

  14.  
  15. [1,2, 3,'hello i am the addone']

2,值傳遞:當傳遞不可變物件時,如果改變引用的值,只是建立了不同的物件,原始物件並沒有改變。

 
  1. def ChangeString(string):

  2. string = 'i changed as this'

  3. print string

  4. return

  5.  
  6. string = 'hello world'

  7. ChangeString(string)

  8. print string

  9.  
  10. 輸出:

  11. i changed as this

  12.  
  13. hello world

四、深拷貝與淺拷貝: 
copy.copy() 淺拷貝;copy.deepcopy() 深拷貝。淺拷貝是新建立了一個跟原物件一樣的型別,但是其內容是對原物件元素的引用。這個拷貝的物件本身是新的,但內容不是拷貝序列型別物件(列表\元組)時,預設是淺拷貝。

1,賦值拷貝: 
賦值,只是建立一個變數,該變數指向原來記憶體地址:n4 = n3 = n2 = n1 = “123/’Wu’” 

2,淺拷貝:在記憶體中只額外建立第一層資料

 
  1. import copy

  2. n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}

  3. n3 = copy.copy(n1)

  • 1
  • 2
  • 3

這裡寫圖片描述

 
  1. import copy

  2. a = [1,[[2,3],5],3]

  3. b = a.copy() #copy.copy(a)

  4.  
  5. print(id(a[1]))

  6. print(id(b[1]))

  7.  
  8. c = copy.deepcopy(a)

  9. print(id(c[1]))

  10.  
  11. 輸出:

  12. 3021497843400

  13. 3021497843400

  14. 3021497854728

3,深拷貝:在記憶體中將所有的資料重新建立一份(排除最後一層,即:python內部對字串和數字的優化)

 
  1. import copy

  2. n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]}

  3. n4 = copy.deepcopy(n1)

相關推薦

Python變數記憶體儲存

這篇文章主要是對python中的資料進行認識,對於很多初學者來講,其實資料的認識是最重要的,也是最容易出錯的。本文結合資料與記憶體

Python 變數

目錄 1.1 註釋 1.2 變數命名 1.3 變數賦值 1.4 同步賦值 1.1 註釋 在 Python 中,使⽤“#”標記註釋。註釋不會被 Python 直譯器執⾏。註釋是開發⼈員⽤來提醒⾃⼰或他⼈程式如何⼯作的重要⼿段,註釋還會⽤在⽂檔的寫作中

Python的生成器表達式(generator expression)

新元素 括號 tuple 列表推導式 特點 解析式 表達式 但是 bracket      介紹     1、生成器表達式(generator expression)也叫生成器推導式或生成器解析式,用法與列表推導式非常相似,在形式上生成器推導式使用圓括號(parenth

Python的join()函數的用法

pre 說明 bsp 字符 指定 .net 絕對路徑 字典 -s 函數:string.join() Python中有join()和os.path.join()兩個函數,具體作用如下: join(): 連接字符串數組。將字符串、元組、列表中的元素以指定的字符(分

舉例Python的split()函數的使用方法

使用方法 imp count say 文章 pri 參考 詳解 參數 這篇文章主要介紹了舉例詳解Python中的split()函數的使用方法,split()函數的使用是Python學習當中的基礎知識,通常用於將字符串切片並轉換為列表,需要的朋友可以參考下 函數:spl

pythonformat函式的強大功能

1、引數替換        format函式可以不限定引數個數,不限定引數位置。        一、不設定指定位置,按預設順序           &nb

[]Python的字串的strip(),lstrip(),rstrip()的含義

轉自:【詳解】python中字串的strip(),lstrip(),rstrip()的含義 【問】 Hi Crifan, 我在http://bbs.csdn.net/topics/390361293 裡看到抓取網易公開課的指令碼,我看了下,感覺還比較簡單,但是有一處不是很理

pythonlist的實現技術-分離式動態順序表!

這是python-list的官方實現方式,但其中關於分離式動態順序表的實現方式描述的不夠細緻,如果你有資料結構基礎的話可以直接去看這篇部落格,如果沒有的話不妨先看看這篇! 什麼事順序表? 將元素順序地存放在一塊連續的儲存區裡,元素間的順序關係由它們的儲存順序自然表示。

pythonpandas.DataFrame.plot( ) 引數secondary_y實現雙座標軸使用

首先看官網的DataFrame.plot( )函式 secondary_y : boolean or sequence, default False # 可以是布林值或者是數列 Whether to plot on the secondary y-axis

Python的join()函式的用法

  函式:string.join() Python中有join()和os.path.join()兩個函式,具體作用如下:     join():    連線字串陣列。將字串、元組、列表中的元素以指定的字元(分隔符)連線生成

Python的join()函式的用法(字串和os.path)

函式:string.join() Python中有join()和os.path.join()兩個函式,具體作用如下: join(): 連線字串陣列。將字串、元組、列表中的元素以指定的字元(分隔符)連線生成一個新的字串 os.path.

Python 的數字型別

Python 3 ⽀持 3 種不同型別的數字型別。 int 整型數字,⽐如 2015。 float 浮點型數字,⽐如 3.14。 complex 複數,⽐如 3+2j。 2.1 檢視變數型別 Python 使⽤內建函式 type() 來檢視變數的型別。在 Python 中,內建

pythonxlrd包的安裝與處理Excel表格

python處理Excel常用到的模組是xlrd。使用xlrd可以非常方便的處理Excel文件,下面這篇文章將給大家詳細介紹python中包xlrd的安裝與利用xlrd處理Excel表格的方法,有需要的朋友們可以參考學習,下面來一起看看吧。 一、安裝xlrd

python的單例模式以及其實現方法

原文出處單例模式 單例模式 單例模式(Singleton Pattern)是一種常用的軟體設計模式,該模式的主要目的是確保某一個類只有一個例項存在。當你希望在整個系統中,某個類只能出現一個例項時,單例物件就能派上用場。 比如,某個伺服器程式的配置資訊存放在一個檔案中,客

Java程式設計師——大牛Nginx系列—Ngx變數

本文來自網路, 在計算機語言中,變數是用來儲存和表示資料的,但不同的語言表示變數的方式不同,像java語言會把變數抽象成各種型別,並且每種型別都會用一個特殊的符號表示,比如表示一個整數需要這樣:      int age= 25;  

Python的Django框架Manager方法的使用

在語句Book.objects.all()中,objects是一個特殊的屬性,需要通過它查詢資料庫。 在第5章,我們只是簡要地說這是模組的manager 。現在是時候深入瞭解managers是什麼和如何使用了。 總之,模組manager是一個物件,Django模組通過它

Python的文字處理

字串 -- 不可改變的序列 如同大多數高階程式語言一樣,變長字串是 Python 中的基本型別。Python 在“後臺”分配記憶體以儲存字串(或其它值),程式設計師不必為此操心。Python 還有一些其它高階語言沒有的字串處理功能。 在 Python 中,字串是“不可改變的序列”。儘管不能“按位置”修改字串

C/C++函式引數傳遞(從記憶體的分析)

   昨天看了記憶體管理的有關內容,有一點了解,但不是很深入,發現之前寫程式碼時有很多細節問題沒有注意到,只知道這樣做可以實現功能,卻不知道為什麼可以這樣,對於採用自己的方法造成的隱患也未知,更不曉得還有其他方法可以實現,我們知道C++強大的一個原因是因為對於一個問題的答案多種解答方法或思路,我想著也許就是

Python的array陣列模組相關使用

初始化array例項化可以提供一個引數來描述允許那種資料型別,還可以有一個初始的資料序列儲存在陣列中。 ? 1 2 3 4 5 6 7 import array import binascii s = 'This is the array.' a =

Python--Pythonre.sub

給出定義: re.sub(pattern, repl, string, count=0, flags=0) Return the string obtained by replacing the leftmost non-overlapping occurr