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,但不能用切片实现

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