Python變量存儲方式以及深淺拷貝
(關於學習廖雪峯Python教程的一些個人總結)
變量存儲
Python是動態語言。
可以把任意數據類型賦值給變量,無需提前聲明變量類型,同一個變量可以反覆賦值,而且可以是不同類型的變量。
下面引用廖雪峯Python教程的簡單例子,描述變量存儲過程:
當我們寫
a = 'ABC'
時,Python解釋器幹了兩件事情:
- 在內存中創建了一個
'ABC'
的字符串;- 在內存中創建了一個名爲
a
的變量,並把它指向'ABC'
。下面程序
a = 'ABC' b = a a = 'XYZ' print(b) # >>> ABC
執行過程:
執行
a = 'ABC'
,解釋器創建了字符串'ABC'
和變量a
,並把a
指向'ABC'
:執行
b = a
,解釋器創建了變量b
,並把b
指向a
指向的字符串'ABC'
:執行
a = 'XYZ'
,解釋器創建了字符串’XYZ’,並把a
的指向改爲'XYZ'
,但b
並沒有更改:所以,最後打印變量
b
的結果是'ABC'
了。
深淺拷貝
Python當中對於拷貝,按照拷貝數據類型分爲兩種類型。一種是數字和字符串的拷貝,另一種就是列表、元組、字典等其他數據結構類型的拷貝。
當然按照深淺也分深拷貝和淺拷貝。
一、數組和字符串拷貝
1、= 賦值
舉例:
a1 = 123
a2 = 123
print(id(a1))
print(id(a2))
結果:(在你的電腦試驗和這裏的地址肯定不同)
140723824476816
140723824476816
原因是Python有一個重用機制,對於同一個數字,Python並不會開闢一塊新的內存空間,而是維護同一塊內存地址,a1,a2變量指向數字123的地址。等同於a2 = a1
,使用字符串賦值也是同理。
結論:對於通過用 = 號賦值,數字和字符串在內存當中用的都是同一塊地址。
2、淺拷貝
舉例:
import copy # 使用淺拷貝需要導入copy模塊
a1 = 123
a3 = copy.copy(a1) # 使用copy模塊裏的copy()函數就是淺拷貝
print(id(a1))
print(id(a3))
結果:(在你的電腦試驗和這裏的地址肯定不同)
140723824476816
140723824476816
發現地址還是一樣。
結論:對於淺拷貝,數字和字符串在內存當中用的也是同一塊地址,和上面講的原理相同。
3、深拷貝
舉例:
import copy
a1 = 123
a4 = copy.deepcopy(a1) # 深拷貝是用copy模塊裏的deepcopy()函數
print(id(a1))
print(id(a4))
結果:(在你的電腦試驗和這裏的地址肯定不同)
140723824476816
140723824476816
發現地址還是一樣。
結論:對於深拷貝,數字和字符串在內存當中用的也是同一塊地址,和上面講的原理相同。
綜上所述,對於數字和字符串的賦值、淺拷貝、深拷貝在內存當中用的都是同一塊地址。
二、字典,列表,元組等數據結構類型拷貝
1、=賦值
舉例:
dict1 = {'k1': 'wu', 'k2': 123, 'k3': {1: 'alex', 2: 678}}
dict2 = dict1
print(id(dict1))
print(id(dict2))
結果:(在你的電腦試驗和這裏的地址肯定不同)
2331901131440
2331901131440
dict2變量只是指向了同一份字典數據的地址,如下圖所示:
理解了上面的圖我們看一下下面的代碼:
dict1 = dict1['k3']
dict2 = dict1
dict2[3] = 'hiahia'
print(dict1)
我們逐步看怎麼執行的:
dict1 = dict1['k3']
dict2 = dict1
dict2[3] = 'hiahia'
print(dict1)
所以結果是:
{1: 'alex', 2: 678, 3: 'hiahia'}
2. 淺拷貝
舉例:
import copy
dict1 = {"k1": "wu", "k2": 123, "k3": {1: 'alex', 2: 678}}
dict3 = copy.copy(dict1) # 淺拷貝
print("第一層字典的內存地址:")
print(id(dict1))
print(id(dict3))
print("第二層嵌套的列表的內存地址:")
print(id(dict1["k3"]))
print(id(dict3["k3"]))
結果:(在你的電腦試驗和這裏的地址肯定不同)
第一層字典的內存地址:
2331901131872
2331901132088
第二層嵌套的列表的內存地址:
2331901155272
2331901155272
結果發現字典第一層確實被拷貝了,變成了兩個,但第二層還是共用相同的數據,如下圖:
結論:所以對於淺拷貝,字典、列表、元組等類型,它們只拷貝第一層地址。
3、深拷貝
舉例:
import copy
dict1 = {"k1": "wu", "k2": 123, "k3": {1: 'alex', 2: 678}}
dict4 = copy.deepcopy(dict1) # 深拷貝
print("第一層字典的內存地址:")
print(id(dict1))
print(id(dict4))
print("第二層嵌套的列表的內存地址:")
print(id(dict1["k3"]))
print(id(dict4["k3"]))
print("第三層嵌套的列表的內存地址:")
print(id(dict1["k3"][1]))
print(id(dict4["k3"][1]))
結果:(在你的電腦試驗和這裏的地址肯定不同)
第一層字典的內存地址:
2331901131872
2331901132376
第二層嵌套的列表的內存地址:
2331901155272
2331901091976
第三層嵌套的列表的內存地址:
2331901150912
2331901150912
發現一二層被拷貝了,最底層的數字和字符串數據依然共用,如下圖:
結論:對於深拷貝,字典、列表、元組等類型,它裏面嵌套多少層,就會拷貝多少層出來,但是最底層的數字和字符串地址不變。