[面试题二]百度资深面试官:python赋值、浅拷贝与深拷贝
链接:https://www.nowcoder.com/discuss/203435?toCommentId=3203149
来源:牛客网
- 『面试题解』百度资深面试官:如何理解Python垃圾回收机制?http://mrw.so/4TrPon
- 『面试题解』百度资深面试官为你解题:线程与进程的区别?http://mrw.so/5ocYjU
内存管理相关的面试一直是面试中的重点考察内容。赋值、深拷贝与浅拷贝是日常编码工作中,需要时常关注的知识点。不小心可是会写出bug哦~
赋值
先来看一段代码,下面两段代码的输出结果会是什么呢?
# case1: 字符串赋值
a = 'linker5'
b = a
a = 'test123'
print('a: {}'.format(a))
print('b: {}'.format(b))
# case2: 列表赋值
c = ['l', 'i', 'n', 'k', 'e', 'r']
d = c
c[0] = 'L'
print('c: {}'.format(c))
print('d: {}'.format(d))
思考中
a: test123
b: linker5
c: ['L', 'i', 'n', 'k', 'e', 'r']
d: ['L', 'i', 'n', 'k', 'e', 'r']
从上面结果可以看到,a的修改没有影响b,但是c的修改了影响了d。这是为什么呢?
首先,非常重要的一点:在python中,都是将“对象的引用(内存地址)”赋值给变量的。其次,在python中有6个标准数据类型,他们分为可变和不可变两类。
不可变类型:该数据类型对象所指定内存中的值不可以被改变。在改变某个对象的值时,由于其内存中的值不可以被改变,所以,会把原来的值复制一份再进行改变,这样就会计算机会开辟一段新的内存空间来存储新的值。如上文中的case1,变量b和a都是字符串对象的引用,当修改变量a或是理解为对a重新赋值时,会赋值一份再进行改变,因此不会影响对象b。
-
Number(数字)
-
String(字符串)
-
Tuple(元组)
可变类型:该数据类型的对象所指定的地址上面的值可以被改变,变量被改变后,其所指向的内存地址上面的值,直接被改变,没有发生复制行为,也没有发生开辟新的内存地址行为。如上文中的case2,变量c是一个可变类型对象,其存储的实际是字符对象的引用地址列表,变量d是可变对象列表的另一个引用。所以当发生改变时,会直接改变c变量列表中的对象值,不会重新开辟空间。
-
List(列表)
-
Dictionary(字典)
-
Set(集合)
浅拷贝
首先,我们需要明确一点,浅拷贝和深拷贝之间的区别只适用于容器对象(包含其他对象的对象,如列表或类实例)。对于非容器对象没有区别,都是对象拷贝,相当于重新赋值,生成一个新的对象。
A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
上面这段话是官方文档上的描述,有2个含义:
1)浅拷贝会创建一个新的容器对象(compound object)
2)对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址)
常见的浅拷贝操作有:
-
使用切片操作[:]
-
使用工厂函数(如list/dir/set)
-
copy模块的copy()方法
深拷贝
A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.
上面这段话是官方文档上的描述,也是有2个含义:
1)深拷贝和浅拷贝一样,都会创建一个新的容器对象(compound object)
2)和浅拷贝的不同点在于,深拷贝对于对象中的元素,深拷贝都会重新生成一个新的对象