python中深浅拷贝是经常出现的,大多数情况下,我们无意识的简单赋值都是浅拷贝的.
那么什么是深拷贝,什么是浅拷贝呢?简单来说,浅拷贝就是创建一个指向被拷贝对象引用(指针)的对象或者变量,显然这是一种指针间的拷贝;深拷贝就不一样了,它是对象内部资源值的拷贝,会在内存中重新开辟一段空间用来存放被拷贝对象的资源.下面通过例子来说明:
>>>a=1
>>>id(a)
>>>21229912
>>>a=2
>>>id(a)
>>>21229888
id(obejct)用于获取变量的内存地址,可见上面的简单赋值告诉我们,对a的赋值语句是基于浅拷贝实现的,不同的值赋给a会使得a指向不同的内存地址.
>>>a=[1,2,3]
>>>b=[i for i in a]
>>>print 'a:%s;b:%s' % (id(a),id(b))
>>>a:140075989324072;b:140075989459024 #a和b的地址不一样,是不是说明就是深拷贝了呢?看看下面
>>>print '%s-%s-%s' % (id(a[0]),id(a[1]),id(a[2]))
>>>21229912-21229888-21229864
>>>print '%s-%s-%s' % (id(b[0]),id(b[1]),id(b[2]))
>>>21229912-21229888-21229864 #可见虽然a和b位于不同的内存空间,但a,b中每个元素都是指向相同空间的,所以还是浅拷贝
>>>a[1]=5
>>>a
>>>[1,5,3]
>>>b
>>>[1,2,3] #为什么b没用变化,应该很好理解吧,简单来说,就是a[1]的指向其他地方了,当然不会影响b
>>>c=a #由于是浅拷贝,故而c和a指向相同的内存地址,所以a的改变一定会影响c
>>>c
>>>[1,5,3]
>>>a[1]=2
>>>a
>>>[1,2,3]
>>>c
>>>[1,2,3]
下面再举一个字典的例子:
>>>a={'name':['John','Mike'],'age':23}
>>>b=a #同上,a和b一样,都是指向相同的空间,相当于C++的引用.但是也有区别,比如说:
>>>b={}
>>>a
>>>{'name':['John','Mike'],'age':23}
>>>c=a.copy() #依旧是浅拷贝
>>>c['age']=24
>>>a
>>>{'name':['John','Mike'],'age':23} #应该知道原因吧,同上.
>>>c['name'].append('Joker')
>>>a
>>>{'name':['John','Mike','Joker'],'age':23} #因为是浅拷贝,故而对列表的修改自然会影响原始的.
那么如何实现深拷贝呢?起始很简单,使用copy模块的deepcopy函数.
>>>a={'name':['John','Mike'],'age':23}
>>>b=deepcopy(a) #深拷贝
>>>b['name'].append('Joker')
>>>a
>>>{'name':['John','Mike'],'age':23}
总结一下,在python中大多数情况下,如果不使用deepcopy的话,都是浅拷贝的,那么对于浅拷贝需要注意:
- 如果是简单类型变量(整型,浮点型,字符串等)的浅拷贝,修改’辅本’并不会影响原始的值.你可以把python的所有变量名看成是一个指针变量,既然是指针变量,你修改了它,也仅仅只是将它指到别的地方,并不会影响原本空间的值.
- 列表,字典等复杂类型变量的浅拷贝,修改列表或者字典的元素,都会改变原始的值,这里的修改包括增加,删除,更新值,不包括这个列表,字典的置空,或者别的整体上的修改,原因很简单修改列表,字典的内部元素,都是在同一个空间做的,所以会影响所有指向该空间的’副本’,但是后者就不同,那就相当于直接到另一个内存空间了.