python提高系列2:详细讲解深拷贝与浅拷贝

这一讲的深浅拷贝对可变类型和不可变类型是有区别的,关于可变类型和不可变类型可以看我的这篇讲解Python提升系列——(1)不可变类型与可变类型

在很多语言中都涉及到深浅拷贝问题,因为在不同的场景中深浅拷贝都有对应的应用,如果用混淆了,则会出现bug。
在讲解深浅拷贝之前,先看一下Python中的赋值问题。

赋值

都知道赋值是通过**“=”**进行的,那将一个变量赋值给另一个变量后,当其中一个变量修改了,另外一个变量会不会变呢?
这个得根据数据是可变类型还是不可变类型分开讲

不可变类型

我在Python提升系列1中讲过不可变类型是指内存和值都不变,包括:数值、字符串、元组和布尔类型。
所以,当一个变量是不可变类型的引用的,当它被赋值给另一个变量后,其中一个的修改,不会影响另外一个变量,因为会重新开辟一块新的内存,变量会指向新的引用。
如:

  • 变量1 = 不可变类型1
  • 变量2 = 变量1
  • 变量1 = 不可变类型2

结果:
变量1 -----> 不可变类型2(地址1)
变量2 -----> 不可变类型1(地址2)

下面看一下代码:

# 数值
num1 = 1
num2 = num1
num2 = 2
print(num1) # 1
print(num2) # 2
print(id(num1)) # 140732872692544
print(id(num2)) # 140732872692576

# 字符串
str1 = "hello"
str2 = str1
str2 = "hello1"
print(str1) # hello
print(str2) # hello1
print(id(str1)) # 1995804017808
print(id(str2)) # 1995810605800

可变类型

相对于不可变类型的赋值,可变类型的赋值会使两个变量指向同一个地址,其中一个变量的修改会影响另一个变量。
可变类型有:列表、字典、集合
下面看一下代码:

# 列表
a = [11, 22]
b = a
a.append(33)
print(a) # [11, 22, 33]
print(b) # [11, 22, 33]
print(id(a)) # 2343423468104
print(id(b)) # 2343423468104


# 字典
c = {"name": "xia"}
d = c

c["age"] = 18
print(c) # {'name': 'xia', 'age': 18}
print(d) # {'name': 'xia', 'age': 18}

print(id(c)) # 1835636063040
print(id(d)) # 1835636063040

# 集合
set1 = {"hello", "world"}
set2 = set1
set1.add("python")

print(set1) # {'python', 'world', 'hello'}
print(set2) # {'python', 'world', 'hello'}
print(id(set1)) # 2145586527816
print(id(set2)) # 2145586527816

深浅拷贝

由于可变类型的赋值,会导致两个变量指向同一块地址,变量的修改会相互影响,于是有了深浅拷贝。

在Python中实现深浅拷贝主要是copy模块。下面讲一下copy模块的使用:

  • copy.copy()被称为浅拷贝
  • copy.deepcopy()被称为深拷贝

不可变类型

看一下分别使用copy.copy()和copy.deepcopy()有什么作用。

copy.copy()

import copy

# 数值
num1 = 1
num2 = copy.copy(num1)
num2 = 2
print(num1) # 1
print(num2) # 2
print(id(num1)) # 140732872692544
print(id(num2)) # 140732872692576

# 字符串
str1 = "hello"
str2 = copy.copy(str1)
str2 = "hello1"
print(str1) # hello
print(str2) # hello1
print(id(str1)) # 1995804017808
print(id(str2)) # 1995810605800

结论:对于不可变类型,可以看到,两个变量还是指向不同的地址,互不影响,与未使用copy.copy()直接赋值的效果一样。

copy.deepcopy()

import copy

# 数值
num1 = 1
num2 = copy.deepcopy(num1)
num2 = 2
print(num1) # 1
print(num2) # 2
print(id(num1)) # 140732872692544
print(id(num2)) # 140732872692576

# 字符串
str1 = "hello"
str2 = copy.deepcopy(str1)
str2 = "hello1"
print(str1) # hello
print(str2) # hello1
print(id(str1)) # 1995804017808
print(id(str2)) # 1995810605800

结论:对于不可变类型,使用copy.deepcopy()与使用copy.copy()、赋值的效果相同。

可变类型

copy.copy()

# 列表
import copy

list1 = [1, 2, 3]
list2 = copy.copy(list1)
list1.append(4)

print(list1) # [1, 2, 3, 4]
print(list2) # [1, 2, 3]
print(id(list1)) # 2056712713736
print(id(list2)) # 2056712711560

print("-------------")

a = [11, 22, [1, 2]]
b = copy.copy(a)
a[-1][-1] = 100
a.append(33)

print(a) # [11, 22, [1, 100], 33]
print(b) # [11, 22, [1, 100]]
print(id(a)) # 2343423468104
print(id(b)) # 2343423468104

copy.deepcopy()

# 列表
import copy

list1 = [1, 2, 3]
list2 = copy.deepcopy(list1)
list1.append(4)

print(list1) # [1, 2, 3, 4]
print(list2) # [1, 2, 3]
print(id(list1)) # 2510491530568
print(id(list2)) # 2510491460296

print("-------------")

a = [11, 22, [1, 2]]
b = copy.deepcopy(a)
a[-1][-1] = 100
a.append(33)

print(a) # [11, 22, [1, 100], 33]
print(b) # [11, 22, [1, 2]]
print(id(a)) # 2510491640584
print(id(b)) # 2510491640328

深浅拷贝与js中的很像,可以参考下图:
在这里插入图片描述

通过大量的例子,我们得出结论:

在不可变数据类型中,深浅拷贝都不会开辟新的内存空间,用的都是同一个内存地址。
在存在嵌套可变类型的数据时,深浅拷贝都会开辟新的一块内存空间;同时,不可变类型的值还是指向原来的值的地址。

不同的是:在嵌套可变类型中,浅拷贝只会拷贝最外层的数据,而深拷贝会拷贝所有层级的可变类型数据。

参考资料:
https://mp.weixin.qq.com/s/e8N-s2w4gYQPKETVH62EAg

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值