本文正在参加「金石计划」
前言
又迎来了一年一度的金三银四,虽然说今年的大环境不好,但是招聘还是在火热进行中。
面试过 Python 工程师的小伙伴都知道,Python 中的浅拷贝和深拷贝是面试高频题,那么接下来,让我们使用 ChatGPT 并结合自己的理解来讲述一下什么是浅拷贝与深拷贝。
正文
话不多说,直接对 ChatGPT 进行提问 Python 中的深拷贝与浅拷贝,结果如下所示:
从上图可以了解到,拷贝是指创建一个数据的副本,而不是与原始数据共享内存空间。
浅拷贝(shallow copy) 是指创建一个新对象,该对象的元素是原始对象的引用。也就是说,新对象的某些部分仍然与原始对象共享内存。这意味着,如果修改新对象中共享的数据,则原始对象也会受到影响。在 Python 中,可以使用切片、copy() 方法或 copy.copy() 函数来执行浅拷贝。
深拷贝(deep copy) 是指创建一个新对象,该对象的所有元素都是原始对象的副本。也就是说,新对象与原始对象没有任何共享内存,因此修改新对象不会影响原始对象。在 Python 中,可以使用 copy.deepcopy() 函数来执行深拷贝。
同时,它还给出了代码,让我们来运行看看:
import copy
original_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
shallow_copy = original_list.copy()
deep_copy = copy.deepcopy(original_list)
original_list[1][1] = 'x'
print(original_list) # [[1, 2, 3], [4, 'x', 6], [7, 8, 9]]
print(shallow_copy) # [[1, 2, 3], [4, 'x', 6], [7, 8, 9]]
print(deep_copy) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
结果也如预测的那样,在原始列表中修改元素后,浅拷贝的结果也被修改了,而深拷贝的结果保持不变。
补充
在正文中可能有部分内容没有介绍到,这里略作一些补充。
首先要明确 Python 中的变量存在 深拷贝 和 浅拷贝 的 区别:
- 对于不可变对象,无论深、浅拷贝,内存地址 (
id
) 都是一成不变的; - 对于可变对象,则存在三种不同情况。
对于不可变对象,举个例子,下面选用字符串 sidiot
作为演示范例:
a = 'sidiot'
b = copy.copy(a)
c = copy.deepcopy(a)
print(id(a), id(b), id(c))
可以得出与上面相符合的结论:对于不可变对象,无论深、浅拷贝,内存地址 (id
) 都是一成不变的;
对于可变对象,同样也举个例子,代码如下所示:
ori = ['sidiot', [521,1314]]
s_copy = copy.copy(ori)
d_copy = copy.deepcopy(ori)
print(id(ori), id(s_copy), id(d_copy))
# 3133870756736, 3133870833024, 3133870832704
可以发现这三个对象的内存地址都是不一样的,因此我们对原列表的外层进行操作时,深浅拷贝的列表都不会发生变化,代码如下:
ori.append('ilvu')
>>> ori
['sidiot', [521, 1314], 'ilvu']
>>> s_copy
['sidiot', [521, 1314]]
>>> d_copy
['sidiot', [521, 1314]]
那如果对其中的可变对象列表进行操作会发生什么呢?
>>> ori[1].append(21)
>>> ori
['sidiot', [521, 1314, 21], 'ilvu']
>>> s_copy
['sidiot', [521, 1314, 21]]
>>> d_copy
['sidiot', [521, 1314]]
这是因为浅拷贝与原对象中的可变对象的内存地址是相同的,即是引用关系。而深拷贝则是实现了完全隔离,所以不受影响。
后记
以上就是 让 ChatGPT 来讲解浅拷贝与深拷贝 的全部内容了,希望大家有所收获!
📝 上篇精讲:【PY】重整 JSON 映射
💖 我是 𝓼𝓲𝓭𝓲𝓸𝓽,期待你的关注,创作不易,请多多支持;
👍 公众号:sidiot的技术驿站;