python06 深浅拷贝原理

preface

这里主要说深浅拷贝的原理。首先说说数字与字符串作为内存对象的重用,请看代码:

a1=12345
b1=12345
a2=a1
print(id(a1),id(b1),id(a2))

打印出来的结果毫无疑问,ID值肯定是一样的。
这就说明在python中,如果内存中有同样的对象(数字与字符串类型),那么我们在申明的时候是直接引用之前有的对象。

浅拷贝

浅拷贝,我们先看代码

n1={'k1':'v1','k2':'v2','k3':{'he':'y1'}}
n2 = copy.copy(n1)
n3 = copy.deepcopy(n1)
print(id(n1),id(n2))
6754632 17766728
print(id(n1['k3']),id(n2['k3']))
6754504 6754504

由打印结果可得,两个字典的ID值不一样了,但是呢,字典包含的value值还是一样的,正如前文说的一样,每个字典的字符串和数字型的元素ID还是一样的,所以说两个字典所引用的元素还是同一个的。请注意看第三个元素,第三个元素的value为字典类型,但是ID值仍是一样的。这就说明了浅拷贝的一个特性,浅拷贝拷贝的时候会把第一层元素一块copy过去,像字典这样有里面还有元素的,浅拷贝就不能把第一层字典里的value再复制过去了。所以我们看第二个print打印出来的结果是一样的。请看下面的一个例子:

n1={'k1':'v1','k2':'v2','k3':{'he':'y1'}}
n2 = copy.copy(n1)

n1['k3']['he'] = 'n1'
n2['k3']['he'] = 'n2'
print(n1,'\n',n2)
{'k1': 'v1', 'k2': 'v2', 'k3': {'he': 'n2'}} 
{'k1': 'v1', 'k2': 'v2', 'k3': {'he': 'n2'}}

如上面的例子所示:由于浅拷贝是引用第一层元素,所以当我们修改n2的时候,也同时把n1修改了,因为他们的k3还是引用同一个值的。

深拷贝

先看代码:

n1={'k1':'v1','k2':'v2','k3':{'he':'y1'}}
n1['k3']['he'] = 'n1'
n3['k3']['he'] = 'n3'
print(n1,'\n',n3)   
{'k3': {'he': 'n1'}, 'k1': 'v1', 'k2': 'v2'} 
{'k3': {'he': 'n3'}, 'k1': 'v1', 'k2': 'v2'}

print(id(n1['k3']),'\n',id(n3['k3']))
6426824 
12110664

我们先看第一个print出来的结果,很显然,n3修改k3的值不会影响n1的k3的值,因为他们现在是两个不同的列表了,我们由第二个print出来的ID值可以看错来,两个k3的值不一样,所以谁也不影响谁,所以深拷贝就是能够把多层元素一块拷贝。

深拷贝 VS 浅拷贝

  • 深拷贝:就是能够把多层元素一块拷贝,后续修改第二层(第三层或者第四层等等)元素的值的时候,不会影响其他深拷贝出来的对象。
  • 浅拷贝:只能复制第一层元素,后续修改第二层(第三层或者第四层等等)元素的值的时候,也会影响其他浅拷贝出来的对象。

深浅拷贝的应用

假设我们有一个模版,内容如下:

info = {
    'cpu':[19],
    'mem':[87],
    'disk':[10],
}

这个时候我们需要在这模版上增加对应的数据,那么就必须要使用深拷贝了,代码如下:

new_info = copy.deepcopy(info)
new_info['cpu'].extend([56,12,32])

打印出来的结果肯定不一样的。

posted @ 2017-03-04 23:31  温柔易淡  阅读(238)  评论(0编辑  收藏  举报