请稍候,加载中....

浅拷贝与深度拷贝

在Python中, 赋值语句属于引用赋值.

引用赋值

什么是引用赋值

将一个变量赋给另一个变量时其实是将两个变量绑定到同一个对象的地址

可以多个变量指向同一个值,这些变量虽然变量名不一样,但是都是同一个对象的引用

引用赋值示例

下面的例子中,lists1引用赋值给lists2,两个列表为同一个对象的引用

lists1 = [[], [], []]
lists2 = lists1
print(lists1 is lists2)

id函数获得变量对象地址

通过id()函数可以查看Python对象的内存地址

每一个变量都有一个对象地址,地址相同的变量是同一个对象

id示例

# 不可变类型重新赋值,id就会发生改变
# 数字类型与字符串类型都是不可变类型
number = 1000
print(id(number))
number += 2000
print(id(number))

上面这个例子,可以观察到进行+运算后,number的id()变了,也就是变为一个新的对象

不可变类型

一旦赋值, 就不能修改值的数据类型.比如数字、字符串、元组

字符串示例

string = "abcd"
print(id(string))
string += "abcd"
print(id(string))

上面这个例子中,同样观察到string的id()结果也变了

元组示例

tuple1 = tuple(1,)
print(id(tuple1))
tuple1 + tuple(2,)
print(id(tuple1))

上面这个例子中, 元组tuple1的id()结果也变了

可变类型

赋值后, 还可以修改值的数据类型, 比如列表、字典、集合

列表示例

lists = ["a", "b", "c"]
print(id(lists))

lists += ["a", "b", "c"]
print(id(lists))

字典示例

dicts = {"a": "A", "b": "B"}
print(id(dicts))
dicts['c'] = "C"
print(id(dicts))

上面这个例子中,lists的id()结果保持不变.

集合示例

sets = {1, 2, 3}
print(id(sets))
sets |= {4}
print(id(sets))

上面这个例子中,sets的id()结果保持不变.

什么是浅拷贝

对于属于同一个对象的两个可变数据类型变量,任意一个对象的值修改,另外一个也会发生变化

lists1 = [1, 2, 3]
lists2 = lists1
# 因为是引用, lists1与lists2指向一个对象
# 修改lists的成员
lists1[0] = [10]
print(lists2)
# 修改lists2的成员
lists2[1] = [100]
print(lists1)

如果不希望lists2与lists1绑定同一个对象, 而仅仅将lists1的值赋给lists2, 可以使用切片赋值来拷贝数据

# 使用切片可以完成浅拷贝
lists3 = lists1[:]
print(id(lists3))
# 对lists3元素重新赋值,不会影响lists1
lists3[0] = [111]
print(lists1)

copy方法

可变类型都有一个内置方法copy()可以实现拷贝

lists1 = [1, 2, 3]
print(id(lists1))
lists3 = lists1.copy()
print(id(lists3))

为什么说是浅拷贝,是因为只有第一层级实现了拷贝赋值,其他层级依然是引用赋值

浅拷贝分析

# lists的成员数据类型也是列表
lists = [[], [], []]
# 浅拷贝
lists4 = lists[:]
# lists与lists4不是同一个对象
print(id(lists4), id(lists))
# 但是对于每个成员来说, 他们还是同一个对象
print("0=>", id(lists4[0]), id(lists[0]))
print("1=>", id(lists4[1]), id(lists[1]))
print("2=>", id(lists4[2]), id(lists[2]))
# 在成员上进行append\pop\extend\del操作,会影响另一个变量的成员值
lists4[0].append(10)
print(lists)
lists1[1].append(20)
print(lists4)

深度拷贝

如果要对列表的每一个层级的成员都要copy赋值,可以使用深拷贝函数deepcopy()

# 深度拷贝
from copy import deepcopy
lists = [[], [], []]
lists5 = deepcopy(lists)
print(id(lists5), id(lists))
print("0=>", id(lists5[0]), id(lists[0]))
print("1=>", id(lists5[1]), id(lists[1]))
print("2=>", id(lists5[2]), id(lists[2]))

可以观察到,使用deepcopy()后的lists5的每个成员都与lists的每个成员的id()结果不一样


Python学习手册-