内存机制:
名词解释:
代码块: 一个函数、一个类‘一个模块、一个文件等都是代码块,总之就是一个块结构
代码块的缓存机制:
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