1.可变数据和不可变数据
- 可变数据 list set dict
当值发生改变的时候 id不会变
list1 = [1,2,3]
list2 = [1,2,3]
print(id(list1),id(list2))
#地址不一样:
39312904 39251208
lst = [1,2,3]
lst2 = [1,2,3]
print(id(lst),id(lst2)) #地址 39185864 39120264
lst2.append(8)
print(id(lst),id(lst2)) #地址 39185864 39120264
#当值发生改变的时候 id不会变
- 不可变数据 int float bool complex str tuple
当值强制性改变的时候 id会改变
a=20
b=20
print(id(a),id(b))
# 地址一样:
8791439221744 8791439221744
#当值强制性改变的时候 id会改变
a=20
b=20
print(id(a),id(b)) #地址 8791439221744 8791439221744
a=99 # 强制改变a的值
print(id(a),id(b)) #地址 8791439224272 8791439221744
# 上面代码打印结果可以看出:由于a的值强制改变,所以a的地址也发生改变,b的地址(id)没改变。
2.赋值 : =
# 可变数据类型第一种情况
lst = [1,2,3]
lst2 = lst
lst.append(5) # 给lst里添加一个元素5
print(lst) # [1,2,3,5] 原来的列表改变
print(lst2 # [1,2,3,5] lst2和lst一样
print(id(lst),id(lst2)) # 32811144 32811144 两个地址是一样的。
#可变数据类型第二种情况
lst = [1,2,3,[5,6,7]]
lst2 = lst
lst[-1].append(0) # 给lst里添加一个元素5
print(lst) #[1, 2, 3, [5, 6, 7, 0]] 原来的列表改变
print(lst2) #[1, 2, 3, [5, 6, 7, 0]] lst2和lst一样
print(id(lst),id(lst2)) #36219080 36219080 两个地址是一样的
# 不可变类型(int,str,tuple)
a = 20
b = a
a = 30 # 修改a的值
print(a) # 30 # 变量a被修改了值
print(b) # 20
print(id(a), id(b)) #地址8791457310000 8791457309680,地址不一样
- =赋值:数据完全共享(=赋值是在内存中指向同一个对象,如果是可变(mutable)类型,比如列表,修改其中一个,另一个必定改变;如果是不可变类型(immutable),比如字符串,修改了其中一个,另一个并不会变
3.浅拷贝
- 属性:浅拷贝,只拷贝一级所有元素,其他层级延续以前的数据。
- 方法一:
List1 = [1,2,3]
List2 = List1.copy() #浅拷贝,复制一份数据重新开辟的空间存储
List1.append(888) # List1添加元素,List1数据改变了。
print(List1) #[1,2,3,88]
print(List2) #[1,2,3] # 复制List1第一层数据,开辟独立空间存储,所以List1数据改变,不会影响到List2的数据。
- 方法二:引入copy模块(推荐)
import copy
List1 = [1,2,3]
List2 = coopy.copy(List1)
List1.append(88)
print(List1) # [1,2,3,88]
print(List2) #[1,2,3]
- 浅拷贝机制
-小示例:
List1 = [1,2,3,[11,22,33]]
List2 = List1.copy()
List1[-1].append(888)
print(List1) #[1,2,3,[11,22,33,88]]
print(List2) #[1,2,3,[11,22,33,88]]
# 为什么List1中数据改变,List2也随着变换呢?如何解决这么尴尬的局面呢,请用深拷贝。
#浅拷贝,只拷贝一级所有元素,其他层级延续以前的数据。List1中二级列表没有被拷贝到List2中,只是引用在List2中,共享二级列表的存储,所有List1中二级列表数据改变,List2中二级列表数据也随着改变。
图解:
4.深拷贝
- 属性:深拷贝,拷贝所有层级的元素都单独拷贝衣服,形成独立的副本。
- 语法:copy.deepcopy(),括号里传出被拷贝的变量名
import copy
List1 = [1,2,3,[11,22,33]]
List2 = copy.deepcopy(List1) # 深拷贝
List1[-1].append(888)
print(List1) #[1,2,3,[11,22,33,88]]
print(List2) #[1,2,3,[11,22,33]] # 深拷贝所有层级数据,都单独拷贝一份,形成独立的副本。
5. 深浅拷贝对比
5.1 浅拷贝指仅仅拷贝数据集合的第一层数据,深拷贝指拷贝数据集合的所有层。所以对于只有一层的数据集合来说深浅拷贝的意义是一样的,比如字符串,数字,还有仅仅一层的字典、列表、元祖等.
- 字符串,数字的深浅拷贝(不可变数据类型)
# 字符串
name = 'beijing' #字符串
name1 = copy.copy(name)
name2 = copy.deepcopy(name)
print(name) # beijing
print(name1) # beijing
print(name2) # beijing
print(id(name),id(name1),id(name2)) #37858480 37858480 37858480地址都一样
# 数字
num=111 #数字
num1=copy.copy(num)
num2=copy.deepcopy(num)
print(id(num),id(num1),id(num2))
#打印结果:地址都一样
8791475138384 8791475138384 8791475138384
如上图,对于数字和字符串的深浅拷贝都只是将变量的索引指向了原来的内存地址,例如在sum,sum1,sum2三个变量中,无论修改任意其中一个变量,只是将其指向了另一个内存地址,其他两个变量不会变,字符串同理。因此,对于 数字 和 字符串 而言,赋值、浅拷贝和深拷贝无意义,因为其永远指向同一个内存地址。
- 列表(字典)的深浅拷贝
- 只有一层的可变数据类型(list,dict等)
import copy lst = [1,2,3,4,5] lst2 = copy.copy(lst) #浅拷贝 lst3 = copy.deepcopy(lst) #深拷贝 print(lst) # [1, 2, 3, 4, 5] print(lst2) # [1, 2, 3, 4, 5] print(lst3) # [1, 2, 3, 4, 5] print(id(lst), id(lst2)) # 32760136 32760328 32760840地址不一样
- 多层可变数据
import copy
lst = [1, 2, 3, 4, 5,[11,22,33]]
lst2 = copy.copy(lst) #浅拷贝
lst3 = copy.deepcopy(lst) #深拷贝
print(lst) # [1, 2, 3, 4, 5, [11, 22, 33]]
print(lst2) #[1, 2, 3, 4, 5, [11, 22, 33]]#浅拷贝
print(lst3) # [1, 2, 3, 4, 5, [11, 22, 33]] #深拷贝
print(id(lst), id(lst2),id(lst3)) # 39316616 39314120 39314632地址不一样
import copy
lst = [1, 2, 3, 4, 5,[11,22,33]]
lst2 = copy.copy(lst) #浅拷贝
lst3 = copy.deepcopy(lst) #深拷贝
lst[-1].append(88) # 修改lst的二层列表数据
print(lst) # [1, 2, 3, 4, 5, [11, 22, 33,88]]
print(lst2) # [1, 2, 3, 4, 5, [11, 22, 33,88]]#浅拷贝
print(lst3) # [1, 2, 3, 4, 5,[11,22,33]] 深拷贝就是数据完完全全独立拷贝出来一份。不会由原先数据变动而变动
print(id(lst), id(lst2),id(lst3)) #39054408 39051912 39052424地址不一样
5.2 拷贝速度对比
- copy 和 deepcopy 谁更快? 浅拷贝!!!
- 原因:浅拷贝,只拷贝外层列表,深拷贝要拷贝深层次的列表,开辟更多的空间,所以浅拷贝速度快。
6.总结
- 浅拷贝:只拷贝一层级所有的元素,其他层级延续以前的数据。copy.copy()或者.copy()。
- 深拷贝:为所有层级的元素都单独开辟新的空间。copy.deepcopy()