小数据池 深浅拷贝

Posted banshannongchang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小数据池 深浅拷贝相关的知识,希望对你有一定的参考价值。

代码块,小数据池

在Python中id是内存地址, 只要创建一个数据(对象)那么都会在内存中开辟一个空间,将这个数据临时加到内存中,这个空间是有一个唯一标识的,就好比是身份证号,标识这个空间的叫做内存地址,也就是这个数据(对象)的id,可以利用id()去获取这个数据的内存地址:

s = "abc"
print(id(s))         #2690615639712

is 和 ==

==是比较两边数据是否相等,而is是判断两边内存地址是否相等.如果两边内存地址相等,那么实际是指向同一个内存地址.

内存地址相同值肯定相同,值相同地址不一定相同.

代码块

代码块:一个模块,一个函数,一个类,一个文件等都是一个代码块。而作为交互方式(在cmd中进入python解释器中)输入的每个命令都是一个代码块。

代码块的缓存机制

前提条件:在同一个代码块内.

机制内容:Python在执行同一个代码块的初始化对象的命令时,会检查是否其值是否已经存在,如果存在,会将其重用。文件执行时(同一个代码块)会把两个变量指向同一个对象,满足缓存机制则他们在内存中只存在一个,即:id相同

适用对象:int(float),str,bool。

具体细则:

int(float):任何数字在同一代码块下都会复用。

bool:True和False在字典中会以1,0方式存在,并且复用。

str:几乎所有的字符串都会符合缓存机制,具体规定如下:

1,非乘法得到的字符串都满足代码块的缓存机制:

s1 = '李白@!#*ewq'
s2 = '李白@!#*ewq'
print(s1 is s2)  # True

2.乘数为1时,任何字符串满足代码块的缓存机制

3.乘数>=2时:仅含大小写字母,数字,下划线,总长度<=20,满足代码块的缓存机制

优点:能够提高一些字符串,整数处理人物在时间和空间上的性能;需要值相同的字符串,整数的时候,直接从‘字典’中取出复用,避免频繁的创建和销毁,提升效率,节约内存。

小数据池

小数据池,不同代码块的缓存机制,也称为小整数缓存机制,或者称为驻留机制

前提条件:在不同代码块

Python自动将-5~256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象。

python会将一定规则的字符串在字符串驻留池中,创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象, 而是使用在字符串驻留池中创建好的对象。

  其实,无论是缓存还是字符串驻留池,都是python做的一个优化,就是将-5~256的整数,和一定规则的字符串,放在一个‘池’(容器,或者字典)中,无论程序中那些变量指向这些范围内的整数或者字符串,那么他直接在这个‘池’中引用,言外之意,就是内存中之创建一个。

适用对象int(float),str,bool

对象细则:

int:对于整数来说,小数据池的范围是-5~256 ,如果多个变量都是指向同一个(在这个范围内的)数字,他们在内存中指向的都是一个内存地址。

str:

1.字符串的长度为0或者1,默认都采用了驻留机制(小数据池)

2.字符串的长度>1,且只含有大小写字母,数字,下划线时,才会默认驻留。

3.乘数为1时:仅含大小写字母,数字,下划线,默认驻留。含其他字符,长度<=1,默认驻留。含其他字符,长度>1,默认驻留。

4.乘数>=2时:仅含大小写字母,数字,下划线,总长度<=20,默认驻留。

5.指定驻留

from sys import intern
a = intern('[email protected]'*20)
b = intern('[email protected]'*20)
print(a is b)
#指定驻留是你可以指定任意的字符串加入到小数据池中,让其只在内存中创建一个对象,多个变量都是指向这一个字符串。

bool值就是True,False,无论你创建多少个变量指向True,False,那么他在内存中只存在一个。

优点:能够提高一些字符串,整数处理人物在时间和空间上的性能;需要值相同的字符串,整数的时候,直接从‘池’里拿来用,避免频繁的创建和销毁,提升效率,节约内存

如果在同一代码块下,则采用同一代码块下的换缓存机制。

如果是不同代码块,则采用小数据池的驻留机制。

深浅拷贝

深浅copy其实就是完全复制一份,和部分复制一份的意思。

1.赋值运算

l1 = [1,2,3,['barry','alex']]
l2 = l1
l1[0] = 111
print(l1)  #[111,2,3,['barry','alex']]
print(l2)  #[111,2,3,['barry','alex']]

对于赋值运算来说,两个变量指向的是同一个内存,因此对一个变量的更改另一个变量也会变.

浅拷贝

对于浅copy来说,只是在内存中重新创建了开辟了一个空间存放一个新列表,但是新列表中的元素与原列表中的元素是公用的。

浅拷贝只对变量的第一层进行拷贝,因此对一个变量的可变元素改变,另一个变量也会改变.

#同一代码块下:
l1 = [1, '太白', True, (1,2,3), [22, 33]]
l2 = l1.copy()
print(id(l1), id(l2))  # 2713214468360 2713214524680   会在内存中开辟新空间存放copy的列表,因此两个列表                                                   id不一样
print(id(l1[-2]), id(l2[-2]))  # 2547618888008 2547618888008    但是列表内容还是沿用之前内容的内存地址
                                                           #因此内容的id相同
print(id(l1[-1]),id(l2[-1]))  # 2547620322952 2547620322952

# 不同代码块下:
>>> l1 = [1, '太白', True, (1, 2, 3), [22, 33]]
>>> l2 = l1.copy()
>>> print(id(l1), id(l2))
1477183162120 1477183162696
>>> print(id(l1[-2]), id(l2[-2]))
1477181814032 1477181814032
>>> print(id(l1[-1]), id(l2[-1]))
1477183162504 1477183162504
l1 = [1, 2, 3, 4, ['alex']]
l2 = l1[::]   #**  相当于浅拷贝
l1[-1].append(666)
print(l2)   #  [1, 2, 3, 4, ['alex',666]]

深拷贝

深拷贝:不可变的数据类型元素会指向原内存地址,而可变的数据类型元素会指向一个新建内存地址.

# 同一代码块下
import copy
l1 = [1, 'alex', True, (1,2,3), [22, 33]]
l2 = copy.deepcopy(l1)
print(id(l1), id(l2))  # 2788324482440 2788324483016
print(id(l1[0]),id(l2[0]))  # 1470562768 1470562768
print(id(l1[-1]),id(l2[-1]))  # 2788324482632 2788324482696
print(id(l1[-2]),id(l2[-2]))  # 2788323047752 2788323047752

# 不同代码块下
>>> import copy
>>> l1 = [1, '太白', True, (1, 2, 3), [22, 33]]
>>> l2 = copy.deepcopy(l1)
>>> print(id(l1), id(l2))
1477183162824 1477183162632
>>> print(id(0), id(0))
1470562736 1470562736
>>> print(id(-2), id(-2))
1470562672 1470562672
>>> print(id(l1[-1]), id(l2[-1]))
1477183162120 1477183162312

以上是关于小数据池 深浅拷贝的主要内容,如果未能解决你的问题,请参考以下文章

Python基础之小数据池及深浅拷贝

小数据池 深浅拷贝

python入门小数据池深浅拷贝集合

python入门小数据池深浅拷贝集合

小数据池和深浅拷贝

集合以及深浅拷贝和和小数据池--个人一些经验总结