赋值,浅拷贝,深拷贝

在 Python 中,浅拷贝、深拷贝和赋值,它们之间的区别在于它们复制对象的方式,具体可以分别如下:

1.赋值(相当于对象引用)

赋值只是将一个变量指向一个已存在的对象,这个变量与这个对象就共享了一个内存地址,当修改这个对象时,所有指向它的变量都会发生变化,例如:

list1 = [1, 2, 3]
list2 = list1  # list2 是 list1 的引用

现在 list2 是 list1 的引用,它们的内存地址相同,所以如果修改 list1, list2 也会相应发生变化:

list1.append(4)
print(list2)  # 输出 [1, 2, 3, 4]

2.浅拷贝

浅拷贝会复制原对象的引用,进而创建一个新的对象,但是这个新的对象中的可变元素与原对象中的元素还是会共享内存地址,对于不可变元素则是复制值,例如:

list1 = [1, 2, [3, 4]]
list2 = list1.copy()  # 进行浅拷贝

虽然 list1 和 list2 现在是两个不同的对象了,但是它们中嵌套的列表还保持着相同的内存地址,意味着如果修改嵌套在列表里面的元素,这两个列表都会改变:

list1[2].append(5)
print(list1)  # 输出 [1, 2, [3, 4, 5]]
print(list2)  # 输出 [1, 2, [3, 4, 5]]

对于不可变对象的浅拷贝

不可变对象指的是如 int、float、str、tuple 等类型的对象,它们的值不能被修改。在浅拷贝不可变对象时,会创建一个新的对象,并将原对象中的元素复制到新的对象中。因为不可变对象是不可变的,所以无论是新的对象还是原来的对象,都无法修改其元素值。因此,浅拷贝会产生一个与原对象独立的新对象。

下面是一个对不可变对象进行浅拷贝的例子:

# 对整数进行浅拷贝
a = 1
b = a.copy()  # 会抛出 AttributeError

这段代码会抛出一个 AttributeError 异常,因为整数对象是不可变类型,不支持 copy() 方法。

对于可变对象的浅拷贝

可变对象指的是如 list、dict、set 等类型的对象,它们的值可以被修改。在浅拷贝可变对象时,会创建一个新的对象(浅拷贝只会拷贝对象的第一层数据),并将原对象中的元素的引用复制到新的对象中。因为新对象中的可变元素只是原对象中可变元素的引用,所以新对象中的元素与原对象中的元素会共享一段内存空间。因此,当修改新对象或原对象的可变元素时,两个对象都会受到影响。

下面是一个对可变对象进行浅拷贝的例子:

# 对列表进行浅拷贝
a = [1, [2, 3]]
b = a.copy()

# 修改 b 列表中第二个元素的值
b[1][0] = 4

print(a)  # [1, [4, 3]]
print(b)  # [1, [4, 3]]

这段代码创建了一个列表对象 a,并将其赋值给变量 b。然后修改 b 列表中第二个元素的值,这也会修改 a 列表中的第二个元素的值。因为 a 和 b 是两个对象,但是它们中的第二个元素都指向了同一个列表对象 [2, 3],所以修改了 b 中的值也会修改 a 中的值。

需要注意的是,浅拷贝只会拷贝对象的第一层,对于嵌套的可变对象,浅拷贝只会拷贝它们的引用,而不会创建新的对象。下面是一个嵌套的列表进行浅拷贝的例子:

# 对嵌套的列表进行浅拷贝
a = [[1, 2], [3, 4]]
b = a.copy()

# 修改 b 列表中第一个元素的值
b[0][0] = 5

print(a)  # [[5, 2], [3, 4]]
print(b)  # [[5, 2], [3, 4]]

这段代码创建了一个嵌套的列表对象 a,并将其赋值给变量 b。然后修改 b 列表中第一个元素的值,这也会修改 a 列表中的第一个元素的值。因为 a 和 b 是两个对象,但是它们中的第一个元素都指向了同一个列表对象 [1, 2],所以修改了 b 中的值也会修改 a 中的值。

总之,对于可变对象的浅拷贝,需要注意其嵌套层数,浅拷贝只会拷贝对象的第一层,如果对象中还嵌套着可变对象,那么这些可变对象只会被拷贝一次,而不会被重新创建。

3.深拷贝

深拷贝会递归地复制嵌套在原始对象中的所有对象,不论这些对象是否可变,这样能够生成一个不同的、完全独立的新对象。例如:

import copy

list1 = [1, 2, [3, 4]]
list2 = copy.deepcopy(list1)  # 进行深拷贝

现在,list1 和 list2 是完全独立的新对象,中嵌套列表的元素也是独立的:

list1[2].append(5)
print(list1)  # 输出 [1, 2, [3, 4, 5]]
print(list2)  # 输出 [1, 2, [3, 4]]

这里修改了 list1 中嵌套列表的值,但是 list2 并没有受到影响,因为它们是完全独立的,共享的内存地址是不同的。

posted @ 2023-04-01 21:53  我不知道取什么名字好  阅读(33)  评论(0编辑  收藏  举报