Python3 中浅拷贝 与 深拷贝 理解

Python3 中浅拷贝 与 深拷贝 理解

我的gitee链接:
00.Python/Chapter03.DataContainers.md · wan230114/PythonNote - 码云 - 开源中国
https://gitee.com/wan230114/PythonNote/blob/master/00.Python/Chapter03.DataContainers.md

(浅层复制 与 深层复制 理解)

浅拷贝 shallow copy
深拷贝 deep copy

总结:

浅拷贝: 是指在复制过程中,只复制一层变量绑定关系,不会复制深层变量绑定的对象的复制过程
深拷贝: 对所有可变对象进行层层复制,实现对象的各自独立。

3.6.3.1. 语法及使用方法:

基本语法:

import copy   # 导入copy模块
L = "任意类型数据"
L2 = copy.copy(L)     # 浅拷贝
L2 = copy.deepcopy(L) # 深拷贝

特别的,在列表中还可以通过切片和自身的copy方法进行浅层复制,如下:

# 浅拷贝
# 1) 利用切片方法。切片——返回切片后的新对象。如
L2 = L[:]
L2 = L[::]
# 2) 利用列表自身方法
L2 = L.copy()
3.6.3.2. 原理理解

图解:

  1. 创建L列表
    创建3个数据对象1, (2, 3), [4, 5],并将其绑定于数据容器对应位置
      L[0]  L[1]           L[2]     # 索引(变量)绑定关系
       |     |             |
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]
  1. 对L浅拷贝绑定X
    最外层可变数据容器重新在内存中另一区域开辟创建, 而内一层所有数据对象, 只是复制了之前的“数据对象”与“变量”的引用绑定关系到当前数据容器,
    因而改变最外层新拷贝对象对原始对象无影响,而改变拷贝后的数据对象如X[2],将会使L[2]也同时发生改变
    如下图:
      L[0]  L[1]           L[2]
       |     |             |
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]
       |     |             |    |     |    |     # 2)内部所有对象正常赋值绑定
    [                                          ] # 1)重新创建最外层可变数据容器
X = [                                          ] # 绑定原始对象关系
      X[0]  X[1]           X[2]     
  1. 对L深拷贝绑定Y
    可以简单理解为所有的数据对象全部在内存中拷贝一份,重新指定绑定关系。
    因而,深拷贝后的数据无论如何操作都将不会影响到之前的数据对象,即改变拷贝后的数据对象如Y[2],不会影响L[2]同时发生改变
    (不过深拷贝的实际情况为了节省计算机资源,只是复制和重新绑定了新的可变数据对象,而其中不可变的数据对象依然保留,重新赋值绑定,这样节省内存资源的同时亦达到了完全拷贝的同样效果。)
      L[0]  L[1]           L[2]
       |     |             |
L = [-10,  (-20, -30),   [-40, -50, (-60, -70)]]
       |     |    |        |    |    |     |      # 2)其余不可变对象正常赋值绑定
    [                    [                    ]]  # 1)重新创建所有可变数据容器
Y = [                    [                    ]]  # 绑定新对象关系
      Y[0]  Y[1]           Y[2]     

注:不论嵌套多少层可变对象,它们最终都会重新复制创建

示例:(验证)

import copy

# 1) L列表的创建
L = [-10,   (-20, -30),   [-40, (-60, -70)]]
Lid = [id(L[0]), id(L[1]), id(L[1][0]), id(L[1][0]), id(L[2][0]), id(L[2][1])]

# 2) 浅拷贝
X = L[:]
Xid = [id(X[0]), id(X[1]), id(X[1][0]), id(X[1][0]), id(X[2][0]), id(X[2][1])]
# 4种浅拷贝方式,效果等价
# X = L[:]
# X = L[::]
# X = L.copy()
# X = copy.copy(L)

# 3) 深拷贝
Y = copy.deepcopy(L)
Yid = [id(Y[0]), id(Y[1]), id(Y[1][0]), id(Y[1][0]), id(Y[2][0]), id(Y[2][1])]

# 对于不可变数据对象的id
print("不可变对象的id", Lid)
print("不可变对象的id", Xid)
print("不可变对象的id", Yid)

# 对于可变数据对象的id
print('原  始', id(L[2]))
print('浅拷贝', id(X[2]))
print('深拷贝', id(Y[2]))

# 改变可变对象
print("L", L)
L[2].append(None)
print('L', L)
print('X', X)  # 绑定的数据对象也被改变
print('Y', Y)  # 可变数据对象已被复制,无影响

"""
不可变对象的id [1785103083024, 1785102803400, 1785074796720, 1785074796720, 1785074796592, 1785105149896]
不可变对象的id [1785103083024, 1785102803400, 1785074796720, 1785074796720, 1785074796592, 1785105149896] 
不可变对象的id [1785103083024, 1785102803400, 1785074796720, 1785074796720, 1785074796592, 1785105149896] 
原  始 1785105256008
浅拷贝 1785105256008
深拷贝 1785105345224
L [-10, (-20, -30), [-40, (-60, -70)]]
L [-10, (-20, -30), [-40, (-60, -70), None]]
X [-10, (-20, -30), [-40, (-60, -70), None]]
Y [-10, (-20, -30), [-40, (-60, -70)]]
"""

练习1:

import copy  # 导入复制模块
L = [3.1, 3.2]
L1 = [1, 2, L]
L2 = copy.deepcopy(L1)  # 实现深拷贝
L[0] = 3.14
print(L1)  # _________
print(L2)  # _________

# [1, 2, [3.14, 3.2]] #此列表由于浅拷贝受影响
# [1, 2, [3.1, 3.2]] #此列表不受影响

练习2:

import copy

a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[4].append('c')

print(a)  # _________
print(b)  # _________
print(c)  # _________
print(d)  # _________

# [1, 2, 3, 4, ['a', 'b', 'c'], 5]  
# [1, 2, 3, 4, ['a', 'b', 'c'], 5]  
# [1, 2, 3, 4, ['a', 'b', 'c']]     
# [1, 2, 3, 4, ['a', 'b']]
"""解析: 
> a: a加了5,a[4]加了'c'  
> b: 赋值绑定操作,与a完全一致  
> c: 浅拷贝了最外层可变对象,最外层不受影响,但内部可变对象受影响  
> d: 深拷贝,所有可变对象不受影响"""
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值