Bootstrap

Python中的深浅拷贝

一. 数据类型

  • 变量:是一个系统表的元素,拥有指向对象的连接空间
  • 对象:被分配的一块内存,存储其所代表的值
  • 引用:是自动形成的从变量到对象的指针
  • 类型:属于对象,而非变量

1. 不可变数据类型

一旦创建就不可修改的对象,包括数值类型、字符串、布尔类型、元组

#定义一个变量a
a = "python"

print(id(a))

在这里插入图片描述

b=10
print(id(b))#140710918126944

b="hello"
print(id(b))#1629196172080

在这里插入图片描述

2. 可变数据类型

可以修改的对象,包括列表、字典、集合
在这里插入图片描述

3. 赋值

只是复制了新对象的引用,不会开辟新的内存空间

a = 10
b = a
print(id(a))#140711658356064
print(id(b))#140711658356064

c = [1, 2, 3]
d = c
print(id(c))#1930836595208
print(id(d))#1930836595208

在这里插入图片描述

二. 深浅拷贝

拷贝就是复制操作,其拷贝的值是相同的,但引用关系有所不同

1. 浅拷贝

浅拷贝,能力有限,只能拷贝最外层对象(只需要为外层开辟内存空间),无法拷贝内层对象

简单的可变数据类型

对于简单的可变数据类型,浅拷贝相当于把原对象的值进行拷贝,需要在内存中开辟一块新的内存空间

import copy

list1 = [1, 3, 5]
list2 = copy.copy(list1)

# 值-相同
print(list1)  # [1, 3, 5]
print(list2)  # [1, 3, 5]

# 地址-不同
print(id(list1))  # 1541605108232
print(id(list2))  # 1541605108296

在这里插入图片描述

复杂的可变数据类型

对于复杂的可变数据类型,浅拷贝只能拷贝可变数据类型的最外层对象,而无法拷贝内层对象,所以只需要为最外层对象开辟内存空间,内层对象拷贝后的引用关系与原对象保持不变

import copy

list1 = [1, 3, 5,[7,9]]
list2 = copy.copy(list1)

# 值-相同
print(list1)  # [1, 3, 5,[7,9]]
print(list2)  # [1, 3, 5,[7,9]]

# 地址-不同
print(id(list1))  # 1541605108232
print(id(list2))  # 1541605108296

# 地址-相同
print(id(list1[3]))  # 2850758572616
print(id(list2[3]))  # 2850758572616

在这里插入图片描述

简单的不可变数据类型

对于简单的不可变数据类型,不可变数据类型地址一旦固定,值就无法改变了,又由于浅拷贝需要把自身的对象空间赋值给另外一个变量,为了保证数据一致,只能让其指向相同的内存空间(不需要额外开辟内存空间)

import copy

a = (1, 3, 5)
b = copy.copy(a)

# 值-相同
print(a)  # (1, 3, 5)
print(b)  # (1, 3, 5)

# 地址-相同
print(id(a))  # 2350406710360
print(id(b))  # 2350406710360

在这里插入图片描述

复杂的不可变数据类型

对于复杂的不可变数据类型,浅拷贝只能拷贝变量的值,无法拷贝内存空间(无法开辟新的内存空间),无法拷贝内层对象

import copy

a = (1, 3, 5, (7, 9))
b = copy.copy(a)

# 值-相同
print(a)  # (1, 3, 5, (7, 9))
print(b)  # (1, 3, 5, (7, 9))

# 地址-相同
print(id(a))  # 2350406710360
print(id(b))  # 2350406710360

# 地址-相同
print(id(a[3]))  # 2109112683592
print(id(b[3]))  # 2109112683592

在这里插入图片描述
无法拷贝内层对象

import copy

a = (1, 3, 5, (7, 9))
b = copy.copy(a)

# 值-相同
print(a)  # (1, 3, 5, [7, 9]))
print(b)  # (1, 3, 5, [7, 9])

# 地址-相同
print(id(a))  # 2350406710360
print(id(b))  # 2350406710360

# 地址-相同
print(id(a[3]))  # 2109112683592
print(id(b[3]))  # 2109112683592

⑤ 浅拷贝栗子

Ⅰ. 切片操作
lst = [1,2,[3,4]]
切片操作:lst1 = lst[:] 或者 lst1 = [each for each in lst]

[:]它与[0:]相似,意思是从0索引拆分到末尾。它返回一个新列表。

Ⅱ. 工厂函数
lst1 = list(lst)
Ⅲ. copy模块中的copy函数
lst1 = copy.copy(lst)

但是在lst中有一个嵌套的list[3,4],如果我们修改了它,情况就不一样了。

2. 深拷贝

深拷贝:和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。

简单的可变数据类型

对于简单的可变数据类型,深拷贝可以对对象进行完全拷贝,生成一块独立的内存空间,两个变量没有任何关系

import copy

a = [1, 3, 5]
b = copy.deepcopy(a)

# 值-相同
print(a)  # [1, 3, 5]
print(b)  # [1, 3, 5]

# 地址-不相同
print(id(a))  # 1763734399496
print(id(b))  # 1763734399560

复杂的可变数据类型

对于复杂的可变数据类型,深拷贝可以对对象进行完全拷贝,不仅可以拷贝外层对象,也可以拷贝内层对象,而且完全独立

import copy

a = [1, 3, 5, [7, 9]]
b = copy.deepcopy(a)

# 值-相同
print(a)  # [1, 3, 5, [7, 9]]
print(b)  # [1, 3, 5, [7, 9]]

# 地址-不相同
print(id(a))  # 2891527236360
print(id(b))  # 2891527236616

# # 地址-不相同
print(id(a[3]))  # 2891527236296
print(id(b[3]))  # 2891527283912

在这里插入图片描述

简单的不可变数据类型

对于简单的不可变数据类型,深拷贝也只能拷贝对象的引用关系,所以看到的记过就是a和b只想了相同的内存空间

import copy

a = (1, 3, 5)
b = copy.deepcopy(a)

# 值-相同
print(a)  # (1, 3, 5)
print(b)  # (1, 3, 5)

# 地址-相同
print(id(a))  # 1719625069656
print(id(b))  # 1719625069656

复杂的不可变数据类型

对于复杂的不可变数据类型,深拷贝也只能拷贝对象的引用关系,所以看到的记过就是a和b只想了相同的内存空间

import copy

a = (1, 3, 5, (7, 9))
b = copy.deepcopy(a)

# 值-相同
print(a)  # (1, 3, 5, (7, 9))
print(b)  # (1, 3, 5, (7, 9))

# 地址-相同
print(id(a))  # 1928373693320
print(id(b))  # 1928373693320

# 地址-相同
print(id(a[3]))  # 1928373701640
print(id(b[3]))  # 1928373701640

3. 深浅拷贝特殊案例

① 可变嵌套不可变类型

外层是可变类型,多以可以进行完全拷贝(需生成内存空间),但内层对象是不可变数据类型,所以只能拷贝引用关系

import copy

a = [1, 3, 5, (7, 9)]
b = copy.copy(a)
c = copy.deepcopy(a)

# 值-相同
print(a)  # [1, 3, 5, (7, 9)]
print(b)  # [1, 3, 5, (7, 9)]
print(c)  # [1, 3, 5, (7, 9)]

# 地址-不同
print(id(a))  # 2197686397896
print(id(b))  # 2197686397960
print(id(c))  # 2197686398216

# 地址-相同
print(id(a[3]))  # 2197686094920
print(id(b[3]))  # 2197686094920
print(id(c[3]))  # 2197686094920

在这里插入图片描述

不可变嵌套可变类型

浅拷贝结论与之前结论一致,都只能拷贝引用关系
深拷贝,有点不同,如果这种类型使用深拷贝,其整体都可以进行完全拷贝

import copy

a = (1, 3, 5, [7, 9])
b = copy.copy(a)
c = copy.deepcopy(a)

# 值-相同
print(a)#(1, 3, 5, [7, 9])
print(b)#(1, 3, 5, [7, 9])
print(c)#(1, 3, 5, [7, 9])

#地址ab同,与c不同
print(id(a))#2983608461896
print(id(b))#2983608461896
print(id(c))#

#地址ab同,与c不同
print(id(a[3]))#2983608498888
print(id(b[3]))#2983608498888
print(id(c[3]))#2983608499144

浅拷贝
在这里插入图片描述
深拷贝
在这里插入图片描述
在这里插入图片描述

4. 总结

① 浅拷贝只能拷贝一层

② 深拷贝能拷贝多层

③ 可变类型拷贝可开辟新的内存空间

④ 不可变类型拷贝对象的引用关系,不可开辟新的内存空间

⑤ 特殊:不可变嵌套可变,深拷贝时,整体都可以进行完全拷贝

;