深拷贝和浅拷贝

赋值、深拷贝、浅拷贝

一、赋值

在Python中,赋值只是创建一个变量,该变量指向原来的内存地址,换句话说就是类似c语言内的指针,用一个指针指向一个元素的内存地址。

In [1]: a = [11, 22]

In [2]: b = a

In [3]: id(a)
Out[3]: 63796288

In [4]: id(b)
Out[4]: 63796288

上面的代码中,我们创建了一个列表a,并且把a赋值给b,此时查看a的id为63796288,而去查看b的id此时同样为63796288。说明在python中,如果使用=来赋值的话,只是将变量指向该元素的内存地址,如果元素发生改变,此时b也会跟着改变。

In [5]: a.append(33)

In [6]: a
Out[6]: [11, 22, 33]

In [7]: b
Out[7]: [11, 22, 33]

二、浅拷贝

浅拷贝是对于一个对象的顶层拷贝。通俗的理解是:拷贝了引用,并没有拷贝内容

In [8]: a = [11, 22]

In [9]: b = [33, 44]

In [10]: c = [a, b]

In [11]: id(a)
Out[11]: 75386152

In [12]: id(b)
Out[12]: 75370248

In [13]: id(c)
Out[13]: 75371024

In [14]: id(c[0])
Out[14]: 75386152

In [15]: id(c[1])
Out[15]: 75370248

In [16]: import copy

In [17]: d = copy.copy(c)

In [18]: d
Out[18]: [[11, 22], [33, 44]]

In [19]: id(d)
Out[19]: 75468472

In [20]: id(d[0])
Out[20]: 75386152

In [21]: id(d[1])
Out[21]: 75370248

上面的代码可以看出,浅拷贝只是将c的最外层放到了一个新的地址,但是里面的内容还是指向c所指向的东西,并没有自己重新创建。如果此时改变a的值,d也会跟着改变。

In [22]: a.append(33)

In [23]: c
Out[23]: [[11, 22, 33], [33, 44]]

In [24]: d
Out[24]: [[11, 22, 33], [33, 44]]

在这里插入图片描述

三、深拷贝

深拷贝是对于一个对象所有层次的拷贝(递归)

In [25]: e = copy.deepcopy(c)

In [26]: e
Out[26]: [[11, 22, 33], [33, 44]]

In [27]: id(e)
Out[27]: 65404976

In [28]: id(e[0])
Out[28]: 75337400

In [29]: id(e[1])
Out[29]: 65407896

从上面也可以看出,e中的所有元素都已经在一个新的地址中,此时如论怎么改变a的值,e都不会跟着改变。

In [30]: a.append(44)

In [31]: a
Out[31]: [11, 22, 33, 44]

In [32]: c
Out[32]: [[11, 22, 33, 44], [33, 44]]

In [33]: d
Out[33]: [[11, 22, 33, 44], [33, 44]]

In [34]: e
Out[34]: [[11, 22, 33], [33, 44]]

四、拷贝的其他方式

4.1 分片表达式可以赋值一个序列

In [1]: a = [11, 22]

In [2]: b = [33, 44]

In [3]: c = [a, b]

In [4]: d = c[:]

In [5]: id(c)
Out[5]: 73034568

In [6]: id(d)
Out[6]: 78822136

In [7]: id(c[0])
Out[7]: 72958200

In [8]: id(d[0])
Out[8]: 72958200
    
In [9]: a.append(3)

In [10]: c
Out[10]: [[11, 22, 3], [33, 44]]

In [11]: d
Out[11]: [[11, 22, 3], [33, 44]]

在这里插入图片描述

4.2 字典的copy方法

In [18]: d = dict(name="summer", age=20)

In [19]: co = d.copy()

In [20]: id(d)
Out[20]: 75186896

In [21]: id(co)
Out[21]: 75250928
    
In [22]: d
Out[22]: {'name': 'summer', 'age': 20}
    
In [23]: co
Out[23]: {'name': 'summer', 'age': 20}

从上面看到,字典的copy与=不一样,并不是指向地址,那它是深拷贝还是浅拷贝呢?

In [29]: d = dict(name="summer", age=20, children_age=[11, 22])

In [30]: co = d.copy()

In [31]: id(d)
Out[31]: 73155856

In [32]: id(co)
Out[32]: 72976640

In [33]: d["children_age"].append(33)

In [34]: d
Out[34]: {'name': 'summer', 'age': 20, 'children_age': [11, 22, 33]}

In [35]: co
Out[35]: {'name': 'summer', 'age': 20, 'children_age': [11, 22, 33]}

因此,我们也可以知道,字典的copy方法也是用的浅拷贝

五、注意点

5.1 浅拷贝对不可变类型和可变类型的copy不同

  • copy.copy对于可变类型,会进行浅拷贝
  • copy.copy对于不可变类型,不会拷贝,仅仅是指向
In [88]: a = [11,22,33]
    
In [89]: b = copy.copy(a)
    
In [90]: id(a)
Out[90]: 59275144
    
In [91]: id(b)
Out[91]: 59525600
    
In [92]: a.append(44)
    
In [93]: a
Out[93]: [11, 22, 33, 44]
    
In [94]: b
Out[94]: [11, 22, 33]
    
In [95]: a = (11,22,33)
    
In [96]: b = copy.copy(a)
    
In [97]: id(a)
Out[97]: 58890680
    
In [98]: id(b)
Out[98]: 58890680

如果一个数元组,那么浅拷贝只是执行了应用(赋值),但是深拷贝还是会进行深拷贝,即递归所有。

# -*- coding: utf-8 -*-
import copy

a = [11, 22]
b = (a, )
c = [b]
d = copy.copy(c)
e = copy.deepcopy(c)
print(id(a))
print(id(b))
print(id(c))
print(id(c[0]))
print(id(d))
print(id(d[0]))
print(id(e))
print(id(e[0]))

有兴趣,也可以执行以下下面的代码,会发现:

12666320
12818128
12667480
12818128
137572640
12818128
13024832
13019824
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值