Python 中的浅拷贝与深拷贝详解
转载请注明出处:https://blog.csdn.net/jpch89/article/details/85028862
1. 浅拷贝
1.1 浅拷贝定义
浅拷贝创建了与某对象具有相同值的 另一个对象,即 两个对象的内存地址不同。
但是,这两个对象 内部的子对象 仍然是同一个对象,即 内部子对象内存地址相同。
简单地说,外层进行了拷贝,内层没有拷贝。
示例如下:
>>> a = [[0, 1], 2, 3]
>>> b = a.copy() # 浅拷贝
>>> print(id(a))
2266074387336
>>> print(id(b)) # 两个父对象内存地址不同
2266074387464
>>> print(id(a[0]))
2266074385160
>>> print(id(b[0])) # 内部子对象内存地址相同
2266074385160
>>> b[0][0] = 666
>>> print(a)
[[666, 1], 2, 3]
>>> print(b)
[[666, 1], 2, 3]
浅拷贝与赋值操作的区别在于,赋值语句得到的对象与原来的对象内存地址是相同的。示例如下:
>>> a = [[0, 1], 2, 3]
>>> b = a # 赋值操作
>>> c = a.copy() # 浅拷贝
>>> print(id(a))
2266074385160
>>> print(id(b))
2266074385160
>>> print(id(c))
2266074387592
1.2 浅拷贝实现
以下方式得到的拷贝都是浅拷贝:
- 切片操作
[:]
- 调用列表、字典、集合的方法
copy()
- 调用内置函数
list()
、dict()
、set()
- 调用标准库模块
copy
中的函数copy()
示例如下:
>>> a = [[0, 1], 2, 3]
>>> b = a[:]
>>> c = a.copy()
>>> d = list(a)
>>> e = copy.copy(a)
>>> print(id(a))
2266074385160
>>> print(id(b))
2266074385800
>>> print(id(c))
2266074385608
>>> print(id(d))
2266074388168
>>> print(id(e))
2266075822792
>>> print(id(a[0]))
2266074387464
>>> print(id(b[0]))
2266074387464
>>> print(id(c[0]))
2266074387464
>>> print(id(d[0]))
2266074387464
>>> print(id(e[0]))
2266074387464
2. 深拷贝
2.1 深拷贝定义
深拷贝创建了与某对象具有相同值的 另一个对象,即 两个对象的内存地址不同。
注解:由此可见,拷贝 这一术语就意味着在内存当中创建原始数据的副本,该副本与原始数据占据不同的内存空间。
同时,这两个对象内部对应的 可变 子对象不是同一个对象,即 可变 子对象的内存地址不同。
简单的说,外层和内层都进行了拷贝。
2.2 深拷贝实现
可以调用标准库模块 copy
中的函数 deepcopy()
实现深拷贝。
示例如下:
>>> a = [[0, 1], 2, 3]
>>> b = copy.deepcopy(a)
>>> print(id(a))
2266074387464
>>> print(id(b))
2266074388168
>>> print(id(a[0]))
2266074385160
>>> print(id(b[0]))
2266075885832
3. 不可变对象的深浅拷贝
- 对于没有嵌套子对象的不可变对象,例如:整数对象、字符串对象和元组对象等,不会进行拷贝(不论是浅拷贝还是深拷贝)。也就是说,不会创建另一个对象,内存地址保持不变,即 深浅拷贝都等同于赋值操作。示例如下:
>>> a = (1, 2, '3') >>> b = copy.copy(a) >>> c = copy.deepcopy(a) >>> print(id(a)) 2266074328016 >>> print(id(b)) 2266074328016 >>> print(id(c)) 2266074328016
- 对于有嵌套子对象的不可变对象,如果子对象是 不可变的,不会进行拷贝,也就是说,不会创建另一个对象,内存地址保持不变,即 深浅拷贝都等同于赋值操作。
>>> a = ((0, 1), 2, 3) >>> b = copy.copy(a) >>> c = copy.deepcopy(a) >>> print(id(a)) 2266074328016 >>> print(id(b)) 2266074328016 >>> print(id(c)) 2266074328016 >>> print(id(a[0])) 2266074460680 >>> print(id(b[0])) 2266074460680 >>> print(id(c[0])) 2266074460680
- 对于有嵌套子对象的不可变对象,如果子对象是 可变的,浅拷贝不会创建另一个对象,内存地址保持不变,即 浅拷贝等同于赋值操作。而深拷贝会创建另一个对象,内存地址改变。
# 浅拷贝 >>> a = ([0, 1], 2, 3) >>> b = a[:] >>> c = copy.copy(a) >>> d = tuple(a) >>> print(id(a)) 2266074327656 >>> print(id(b)) 2266074327656 >>> print(id(c)) 2266074327656 >>> print(id(d)) 2266074327656 >>> print(id(a[0])) 2266075822856 >>> print(id(b[0])) 2266075822856 >>> print(id(c[0])) 2266075822856 >>> print(id(d[0])) 2266075822856 # 深拷贝 >>> e = copy.deepcopy(a) >>> print(id(a)) 2266074327656 >>> print(id(e)) 2266074507880 >>> print(id(a[0])) 2266075822856 >>> print(id(e[0])) 2266074385608
完成于 2018.12.16