【Python】Python中的深浅拷贝

在Python中其实一切都是对象,甚至连type其本身都是对象,type对象
变量-引用-对象(可变对象,不可变对象)-切片-拷贝(浅拷贝,深拷贝)
比如对a = 3来说,首先其值为3,然后告诉Python,它是一个int类型的对象,相当于指向int类型的指针

  • Python中的可变对象

    • 可以修改的对象,如 list, dict
  • Python中的不可变对象

    • 不可以修改的对象,如 str, tuple, number

拷贝

  • 深拷贝(deepcopy)

    • copy模块的deepcopy方法,完全复制了父对象及其子对象
  • 浅拷贝(shallow copy)

    • copy模块的copy方法,复制父对象,不会复制对象内部的子对象,而是引用子对象的地址

只有一级对象

D = {
    
    'name': "zdz", "age" : 20}
import copy
C1 = copy.copy(D)
C2 = copy.deepcopy(D)
print(id(C1), id(C2), id(D))
# 2143080833472 2143080875968 2143080833408
print(C1, C2, D)
# {'name': 'zdz', 'age': 20} {'name': 'zdz', 'age': 20} {'name': 'zdz', 'age': 20}
C1['age'] = 22
print(C1)
# {'name': 'zdz', 'age': 22}
D['age'] = 22
print(D) # {'name': 'zdz', 'age': 22}
print(C1, C2) # 不变

多级对象

import copy
D = {
    
    
    'name':{
    
    'first': 'james', 'last':'tom'},
    'age':[12, 13]
}
C1 = copy.copy(D)
C2 = copy.deepcopy(D)
D['age'][0] = 14
print(D)  # {'name': {'first': 'james', 'last': 'tom'}, 'age': [14, 13]}
print(C1)  # 浅拷贝 {'name': {'first': 'james', 'last': 'tom'}, 'age': [14, 13]}
print(C2)  # 深拷贝 {'name': {'first': 'james', 'last': 'tom'}, 'age': [12, 13]}

C1['age'][0] = 24
print(D)  # {'name': {'first': 'james', 'last': 'tom'}, 'age': [24, 13]}  
# 可以看到改变浅拷贝之后的字典 源字典也跟着改变了 它们会相互影响

结论

  • 深浅拷贝都创建新的对象,所以id()返回的值不同,浅拷贝的元素使用原始元素的引用或者地址,深拷贝的元素重新拥有新的地址,是一个完全独立的对象。
  • 深浅拷贝都占用不同的内存空间
  • 如果只有一层顶级对象,那么改变原字典之后,深浅拷贝的字典都不会改变
  • 如果有多级对象,那么改变原字典之后,深拷贝的字典不会改变,浅拷贝的字典会改变

切片技术

  • 切片技术用于所有的序列,如字典、列表、元组。
    • 切片不能直接用于字典,只能使用dict.copy()或者dict.deepcopy()

单级列表的切片

L = list(range(10))
L1 = L[4:]
# L[9] = 1000
L1[2] = 1000  # 修改拷贝之后的值
print(L) #  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  # 源列表不变
L[5] = 111  # 修改源列表
print(L1) # [4, 5, 1000, 7, 8, 9] # 拷贝之后的值也不变

多级列表的切片

L1 = [8, 9, 10, 11, [1, 2, 3, 4]]
L2 = L1[2:]
print(L2)  # [10, 11, [1, 2, 3, 4]]
L1[4][0] = 0  # 修改源列表的子对象
print(L2)  # [10, 11, [0, 1, 2, 3]] L2拷贝的子对象值改变
L1[0] = 0  # 修改源列表的父对象(顶级对象)
print(L2)  # [10, 11, [0, 1, 2, 3]] L2拷贝的顶级对象值未改变
# 可以得出切片操作其实是一种浅拷贝 对只有一层顶级对象的值来说,修改浅拷贝之后的值源列表都不会变
# 修改多级子对象的值,则浅拷贝之后的值会受影响

# 同理,修改拷贝之后的列表 顶级对象和子对象值 源列表也会作出相应的改变
L2[0] = 1000
print(L1)  # [0, 9, 10, 11, [0, 2, 3, 4]]
L2[2][0] = 111
print(L1)  # [0, 9, 10, 11, [111, 2, 3, 4]]

结论

  • 切片实际是一种浅拷贝操作,只拷贝顶级对象数据,子对象则拷贝对象的地址。
  • 浅拷贝可以节省内存空间。

猜你喜欢

转载自blog.csdn.net/qq_41139677/article/details/120517850
今日推荐