在过往的面试中,面试最频繁的题目之一就要属赋值、深拷贝与浅拷贝这个问题的原理了,今天就来带大家解析这个问题。
首先,这个问题设计的知识点是什么?大家必须先搞清楚这个问题。这个问题涉及到了我们计算机的底层----内存。那么我们现在怎么来解析这个问题呢?这个问题问我们的是赋值、深拷贝和浅拷贝在我们的内存当中到底是一个什么样的体现形式。
大家都知道,万物皆对象,对象就是内存分配的一块存储区域,那么这个问题的通俗说法就是,赋值有没有在内存当中划分区域,深拷贝和浅拷贝划分区域有什么区别?我们一个个来讲
赋值
赋值即给值赋予一个变量(名称),使得我们可以使用到这个值。
在内存中存在几种id固定不变的数据:int类型、字母、空格等
对于id不定不变的数据,若同时赋值给两个变量,那么两个变量就是同一个对象,都会指向这个值所在的内存地址。
a = 123
b = 123
print(id(a), id(b))
执行结果:
(1590328144, 1590328144)
那么其他的数据类型(比如字符串,列表,字典等),如果同时赋值给两个变量,那么他们就是两个对象,分别指向各自数据的内存地址。
a = [1, 2, 3]
b = [1, 2, 3]
print(id(a), id(b))
执行结果:
1881566679560 1881566679240
如果不给b赋值,直接令b = a,那么他们就是一个引用的关系,b引用a的对象,会指向a所在的内存地址。(我们在面试过程中被问到赋值,通常面试官也是指这个现象,回答这个即可)
a = [1, 2, 3]
b = a
print(id(a), id(b))
执行结果:
2166563410440 2166563410440
浅拷贝
这里我们会用到一个库copy(python自带的)。浅拷贝的意思就是当一个数据有数据类型嵌套的情况存在时(例如[1,2,[3,4,5]]),只能将外面那层数据拷贝出来成为一个完全独立的个体,也就是说生成一个新的对象,而第二层数据无法拷贝出来,只是引用过来而已,内存地址不变,这就会造成一个现象:修改其中一个对象的外层数据,另一个对象的数据不会发生变化,而修改其中一个对象的内层数据,另外一个对象的数据也会发生变化。
import copy
a = [1, 2, 3, [4, 5, 6]]
# 浅拷贝
b = copy.copy(a)
# 修改第一层数据
a[0] = 10
print(a)
print(b)
print(id(a), id(b))
执行结果:
[10, 2, 3, [4, 5, 6]]
[1, 2, 3, [4, 5, 6]]
1724296570184 1724296571464
import copy
a = [1, 2, 3, [4, 5, 6]]
# 浅拷贝
b = copy.copy(a)
# 修改第二层数据
a[3][0] = 10
print(a)
print(b)
print(id(a), id(b))
执行结果:
[1, 2, 3, [10, 5, 6]]
[1, 2, 3, [10, 5, 6]]
1813604181320 1813604182600
深拷贝
深拷贝和浅拷贝的区别就是,不管数据类型中嵌套了多少个数据类型,它会把所有的数据都完全拷贝出来成为一个全新的对象,修改其中任何一个数据都不会影响另外一个对象的数据。
import copy
a = [1, 2, 3, [4, 5, 6]]
# 深拷贝
b = copy.deepcopy(a)
# 修改第二层数据
a[3][0] = 10
print(a)
print(b)
print(id(a), id(b))
执行结果:
[1, 2, 3, [10, 5, 6]]
[1, 2, 3, [4, 5, 6]]
2274488001864 2274488003144
结语
那么看到这儿,大家对我们这个赋值、浅拷贝和深拷贝明白了吗?赋值就是将对象的数据直接拿过来用,并不会改变内存地址。浅拷贝会讲对象数据的第一层拷贝出来成为一个新的对象,所以地址改变了,但是第二层乃至更深层的数据只会引用过来,并不会生成一个新的地址,所以改变它里面的数据两个对象的数据都会发生变化。深拷贝则会把所有的数据全部拷贝成为一个新的对象,地址完全改变,所以改变其中一个对象的数据,另一个对象不受影响。
以后大家遇上了这个问题,以这样的方式去回答,绝对是满分。