python的內存機制和深淺copy

內存機制:

名詞解釋:
代碼塊: 一個函數、一個類‘一個模塊、一個文件等都是代碼塊,總之就是一個塊結構

代碼塊的緩存機制:
1)前提:同一個代碼塊
2)機制:在執行同一個代碼塊時,如果初始化一個新的對象時,其值已經在內存中存在(以字典或者其他方式管理),則重用這個值。

3)具體:
int(float):任何數字在同一代碼塊下都會重用。
bool:True和False在字典中會以1、0的方式存在,並且複用。
str: 就是短的會重用,或者稍長一點,用*1的方法賦值會重用。

小數據池:

1)前提條件:不同代碼塊。
2)機制:
對於數字,python自動在內存中緩存-5~256的數字,然後使用這些值的時候複用這些值。
對於字符串,python會將符合一定規則的字符串存在字符串駐留池中。使用的時候複用它們
3)具體:
int :對於數字,python自動在內存中緩存-5~256的數字,然後使用這些值的時候複用這些值。
str:1,字符串的長度爲0或者1,默認都採用了駐留機制(小數據池)
2,字符串的長度>1,且只含有大小寫字母,數字,下劃線時,纔會默認駐留。
3.1 乘數爲1時:僅含大小寫字母,數字,下劃線,默認駐留含其他字符,長度<=1,默認駐留。含其他字符,長度>1,默認駐留。
3.2 乘數>=2時:僅含大小寫字母,數字,下劃線,總長度<=20,默認駐留。
##### 總的來說,還是較的字符串纔會採用駐留機制

指定駐留:

可以自定義駐留字符串:
from sys import intern
a = intern(‘hello!@’*20)
b = intern(‘hello!@’*20)
print(a is b)
#指定駐留是你可以指定任意的字符串加入到小數據池中,讓其只在內存中創建一個對象,多個變量都是指向這一個字符串。

總結:
  如果在同一代碼塊下,則採用同一代碼塊下的換緩存機制。

如果是不同代碼塊,則採用小數據池的駐留機制。

賦值、深淺copy:

首先了解可變對象和不可變對象。
不可變對象: 一旦創建就不可修改,包括字符串,元組,數字
可變對象: 可以修改內容的對象,包括列表、字典。

賦值: 即兩個變量指向同一個內存地址。
對於不可變對象:更改變量的值相當於變量指向了新的內存地址

	print("1:")
	a = 2
	b = a
	print(id(a))
	print(id(b))
	print("2:")
	a = 3
	print(id(a))
	print(id(b))
	
	輸出:
	1:
	140713763381680
	140713763381680
	2:
	140713763381712
	140713763381680
	
	
	對於可變對象:  更改變量內部的值,相當於對指向內存地址內的內容做了更改,會導致指向同一塊內存的變量內容均發生改變。
	
	la = [1, 2, 3, 4, 5]
	lb = la
	print("1:")
	print(id(la))
	print(id(lb))
	print(la)
	print(lb)
	
	#改變變量指向內存中的內容。
	la[0] = 0
	print("2:")
	print(id(la))
	print(id(lb))
	print(la)
	print(lb)
	
	輸出:
	***1***:
	2088964757640
	2088964757640
	[1, 2, 3, 4, 5]
	[1, 2, 3, 4, 5]
	***2****:
	2088964757640
	2088964757640
	[0, 2, 3, 4, 5]
	[0, 2, 3, 4, 5]

深淺copy針對頂級對象是可變對象來說的

淺copy:對於頂級對象,即變量指向的地址不同,但是內存中內容的地址一樣,如果更改其中一個變量內部的不可變內容,則對其他變量不產生影響;如果更改其中一個變量內部可變內容的話,則對其他變量也有影響。

比如對列表la,lb(其中lb使用lb=la.copy()得到)而言,id(la)和id(lb)不同,而id(la[0]), id(la[1]), id(la[2])…和id(lb[0]), id(lb[1]), id(lb[2])…的內存地址相同
如果la[0]是不可變內容比如數字,改變la[0]的值,則對lb[0]不會產生影響。
如果la[1]是可變內容比如列表,刪除la[1]中的一個元素,則lb[1]會有相同的變化,因爲他們指向同一個內存嘛,當然會同時改變了。

例子:
	la = [1, 2, [3, 4, 5], "abcd"]
	lb = la.copy()
	print("***1***:")
	print("變量指向的地址(頂級對象):",id(la))
	print("變量指向的地址(頂級對象):",id(lb))
	print(la)
	print(lb)
	print("變量內容的地址(二級對象):", "la[0]:",id(la[0]), "la[2]:", id(la[2]), "la[3]:", id(la[3]))
	print("變量內容的地址(二級對象):", "lb[0]:",id(lb[0]), "lb[2]:", id(lb[2]), "lb[3]:", id(lb[3]))

	print("***2***:")
	la[0] = 0
	la[2].append(0)
	la[3] += "123"

	print("變量指向的地址(頂級對象):",id(la))
	print("變量指向的地址(頂級對象):",id(lb))
	print(la)
	print(lb)
	print("變量內容的地址(二級對象):", "la[0]:",id(la[0]), "la[2]:", id(la[2]), "la[3]:", id(la[3]))
	print("變量內容的地址(二級對象):", "lb[0]:",id(lb[0]), "lb[2]:", id(lb[2]), "lb[3]:", id(lb[3]))

輸出:
	***1***:
	變量指向的地址(頂級對象): 2562866893768
	變量指向的地址(頂級對象): 2562868158408
	[1, 2, [3, 4, 5], 'abcd']
	[1, 2, [3, 4, 5], 'abcd']
	變量內容的地址(二級對象): la[0]: 140713763381648 la[2]: 2562866893256 la[3]: 2562868424112
	變量內容的地址(二級對象): lb[0]: 140713763381648 lb[2]: 2562866893256 lb[3]: 2562868424112
	***2***:
	變量指向的地址(頂級對象): 2562866893768
	變量指向的地址(頂級對象): 2562868158408
	[0, 2, [3, 4, 5, 0], 'abcd123']
	[1, 2, [3, 4, 5, 0], 'abcd']
	變量內容的地址(二級對象): la[0]: 140713763381616 la[2]: 2562866893256 la[3]: 2562887654640
	變量內容的地址(二級對象): lb[0]: 140713763381648 lb[2]: 2562866893256 lb[3]: 2562868424112

深copy:深copy需要藉助copy模塊完成,詳情見代碼。

深copy:深copy之後的兩個變量之間不存在什麼關聯。深copy後變量指向的地址不同,且內容中可變內容的地址也不同,因此其中一個變量內容無論怎麼更改,均不會對另一個變量產生影響。

例子:
	import copy

	la = [1, 2, [3, 4, 5], "abcd"]
	lb = copy.deepcopy(la)
	print("***1***:")
	print("變量指向的地址(頂級對象):",id(la))
	print("變量指向的地址(頂級對象):",id(lb))
	print(la)
	print(lb)
	print("變量內容的地址(二級對象):", "la[0]:",id(la[0]), "la[2]:", id(la[2]), "la[3]:", id(la[3]))
	print("變量內容的地址(二級對象):", "lb[0]:",id(lb[0]), "lb[2]:", id(lb[2]), "lb[3]:", id(lb[3]))

	print("***2***:")
	la[0] = 0
	la[2].append(0)
	la[3] += "123"

	print("變量指向的地址(頂級對象):",id(la))
	print("變量指向的地址(頂級對象):",id(lb))
	print(la)
	print(lb)
	print("變量內容的地址(二級對象):", "la[0]:",id(la[0]), "la[2]:", id(la[2]), "la[3]:", id(la[3]))
	print("變量內容的地址(二級對象):", "lb[0]:",id(lb[0]), "lb[2]:", id(lb[2]), "lb[3]:", id(lb[3]))

輸出:
	***1***:
	變量指向的地址(頂級對象): 2450022407880
	變量指向的地址(頂級對象): 2450002301896
	[1, 2, [3, 4, 5], 'abcd']
	[1, 2, [3, 4, 5], 'abcd']
	變量內容的地址(二級對象): la[0]: 140713763381648 la[2]: 2450022311560 la[3]: 2450003832304
	變量內容的地址(二級對象): lb[0]: 140713763381648 lb[2]: 2450023326088 lb[3]: 2450003832304
	***2***:
	變量指向的地址(頂級對象): 2450022407880
	變量指向的地址(頂級對象): 2450002301896
	[0, 2, [3, 4, 5, 0], 'abcd123']
	[1, 2, [3, 4, 5], 'abcd']
	變量內容的地址(二級對象): la[0]: 140713763381616 la[2]: 2450022311560 la[3]: 2450023325936
	變量內容的地址(二級對象): lb[0]: 140713763381648 lb[2]: 2450023326088 lb[3]: 2450003832304

補充:切片可以用於序列,即元組,列表,字符串(不能用於字典)。切片賦值相當於淺copy。

字典可以使用深淺copy,但不能用切片實現

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