3.1.2 默认浅复制

根据上一节的描述,直接把变量赋值给另一个变量, 还算不上复制:

a = [1, 2, 3]
b = a
b == a   # True,等同性校验,会调用 __eq__ 函数,这里只判断内容是否相等
b is a   # True,一致性校验,会检查是否是同一个对象,调用 hash() 函数,可以理解为比较指针

可见不仅仅数组相同,就连变量也是相同的,可以把 b 理解为 a 的别名。

如果用切片,或者数组的构造函数来创建新的数组,得到的是原数组的浅拷贝:

a = [1, 2, 3]
b = list(a)
b == a   # True,因为数组内容相同
b is a   # False,现在 a 和 b 是两个变量,恰好指向同一个数组对象

但如果数组中的元素是可变的,可以看到这些元素并没有被完全拷贝:

a = [[1], [2], [3]]
b = list(a)
b[0].append(2)
a # 得到 [[1, 2], [2], [3]],因为 a[0] 和 b[0] 其实还是挂在相同对象上的不同标签

如果想要深拷贝,需要使用 copy 模块的 deepcopy 函数:

import copy 

b = copy.deepcopy(a)
b[0].append(2)
b  # 变成了 [[1, 2], [2], [3]]
a  # 还是 [[1], [2], [3]]

此时,不仅仅是每个元素的引用被拷贝,就连每个元素自己也被拷贝。所以现在的 a[0]b[0] 是指向两个不同对象的两个不同变量(标签),自然就互不干扰了。

如果要实现自定义对象的深复制,只要实现 __deepcopy__ 函数即可。这个概念在几乎所有面向对象的语言中都会存在,就不详细介绍了。

Last updated