Python變量存儲方式以及深淺拷貝

Python變量存儲方式以及深淺拷貝

(關於學習廖雪峯Python教程的一些個人總結)

變量存儲

Python是動態語言。

可以把任意數據類型賦值給變量,無需提前聲明變量類型,同一個變量可以反覆賦值,而且可以是不同類型的變量。

下面引用廖雪峯Python教程的簡單例子,描述變量存儲過程:

當我們寫

a = 'ABC'

時,Python解釋器幹了兩件事情:

  1. 在內存中創建了一個'ABC'的字符串;
  2. 在內存中創建了一個名爲a的變量,並把它指向'ABC'

下面程序

a = 'ABC'
b = a
a = 'XYZ'
print(b)
# >>> ABC

執行過程:

執行a = 'ABC',解釋器創建了字符串'ABC'和變量a,並把a指向'ABC'

py-var-code-1

執行b = a,解釋器創建了變量b,並把b指向a指向的字符串'ABC'

py-var-code-2

執行a = 'XYZ',解釋器創建了字符串’XYZ’,並把a的指向改爲'XYZ',但b並沒有更改:

py-var-code-3

所以,最後打印變量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

發現一二層被拷貝了,最底層的數字和字符串數據依然共用,如下圖:

在這裏插入圖片描述

結論:對於深拷貝,字典、列表、元組等類型,它裏面嵌套多少層,就會拷貝多少層出來,但是最底層的數字和字符串地址不變。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章