內存機制:
名詞解釋:
代碼塊: 一個函數、一個類‘一個模塊、一個文件等都是代碼塊,總之就是一個塊結構
代碼塊的緩存機制:
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