今天面试了一个计算机专业研究生且大学出身也很好,但是面试的结果来看并没有达到我的预期。很多基础计算机的知识貌似都不是很懂,更别说对操作系统、编译原理和算法的深度造化了。不排除高级语言和IDE隐藏了很多细节,但是当你去追求更高性能或者你想进阶的话,我想说底层的东西真的很重要。只有你完全掌握这些底层的东西,你才能通过高级语言特性来优化你的业务和应用。虽然有点扯淡,还是开始咱们今天聊一下Python的浅拷贝和深度拷贝。
在Python中大致可以分为immutable和mutable两种数据类型,比如:字符串字面值、数字、元组等这些是immutable类型,列表、字典等是mutable类型。我们先来看一下python对象赋值是如何赋值的?
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from copy import copy,deepcopy
adr = lambda x:hex(id(x))
def test(count=None):
print"test method before id ",adr(count)
if type(count)==list:
count.append(1)
else:
count+=1
print"test method after id ",adr(count)
if __name__ == "__main__":
a,b = 1,1
c,d = [],[]
print"a,b,c,d id ",map(adr,(a,b,c,d))
print"1,1,[],[] id ",map(adr,(1,1,[],[]))
print"c=",c
test(c)
print"c=",c
print"a=",a
test(a)
print"a=",a
运行结果如下所示:
a,b,c,d id ['0x10030c0b8', '0x10030c0b8', '0x10269c488', '0x1006ea200']
1,1,[],[] id ['0x10030c0b8', '0x10030c0b8', '0x102693320', '0x10269ec68']
c= []
test method before id 0x10269c488
test method after id 0x10269c488
c= [1]
a= 1
test method before id 0x10030c0b8
test method after id 0x10030c0a0
a= 1
我们先分析一下我们所写的代码,我们新建了四个变量分别为a,b,c和d。其中都为相同的字面值或者说都是相同的object,在python一切皆对象。我们看到immutable类型是赋值操作是直接传递内存地址;而对于mutable类型,赋值操作定义一个新的对象,将右值对象内存地址传递给这个新的对象。函数参数传递是按照内存地址传递,其引用传递。
我们先看一下Demmo:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from copy import copy,deepcopy
adr = lambda x:hex(id(x))
if __name__ == "__main__":
p = ['brian',25,["python"]]
p1 = copy(p)
print"p id,p1 id",map(adr,(p,p1))
print"p element id==",map(adr,p)
print"p1 element id==",map(adr,p1)
print".....change ......"
p[0]="lv"
p[1]=1111
p[2].append(12)
print"p element id==",map(adr,p)
print"p1 element id==",map(adr,p1)
运行结果如下所示:
p id,p1 id ['0x10399e320', '0x103ac5950']
p element id== ['0x103aae990', '0x10030be78', '0x1006ea200']
p1 element id== ['0x103aae990', '0x10030be78', '0x1006ea200']
.....change ......
p element id== ['0x1021bbd78', '0x102068218', '0x1006ea200']
p1 element id== ['0x103aae990', '0x10030be78', '0x1006ea200']
非常清晰的可以看到,浅拷贝对于immutable类型来说是拷贝了一个不可变的对象的引用, 修改你得到的变量只会让该变量的引用指向一个新的对象,而对于mutable类型来说还是对象引用。使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用. 看一下产生浅拷贝的效果操作:
深拷贝是完全真正意义上的拷贝,是完全复制所有对象元素。但是对于原子类型对象(immutable)是没有深拷贝这么一说的。先来看一下例子:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from copy import copy,deepcopy
adr = lambda x:hex(id(x))
if __name__ == "__main__":
p = ['brian',25,["python"]]
p1 = deepcopy(p)
print"p id,p1 id",map(adr,(p,p1))
print"p element id==",map(adr,p)
print"p1 element id==",map(adr,p1)
print".....change ......"
p[0]="lv"
p[1]=1111
p[2].append(12)
print"p element id==",map(adr,p)
print"p1 element id==",map(adr,p1)
运行结果如下:
p id,p1 id ['0x101e93320', '0x101e9eef0']
p element id== ['0x101fab990', '0x10030be78', '0x1006ea200']
p1 element id== ['0x101fab990', '0x10030be78', '0x101e9cf38']
.....change ......
p element id== ['0x1019bbd78', '0x100733f48', '0x1006ea200']
p1 element id== ['0x101fab990', '0x10030be78', '0x101e9cf38']
deepcopy是完全意义上的copy,实现了真正的隔离。