在比较深拷贝和浅拷贝之前,要先理解python的可变类型的变量和不可变类型的变量。
python中数字,字符串,元组就是典型的不可变类型的变量。对于不可变类型的变量,改变它们的值其实就是在内存中新建了一个变量。如:
>>> a=120;b="ACS";c=(11,22,23);print(id(a),id(b),id(c))
10923232 140086869042264 140086868265720
>>> a+=120;b=b+"ACA";c=(11,22,21,21);print(id(a),id(b),id(c))
10927072 140086899703008 140086899571352
>>> a,b,c
(240, 'ACSACA', (11, 22, 21, 21))
注意,元组是不可变类型的变量,但是如果元组里的元素是可变类型则可以改变。如:
元组 a=(12,'ABC',[12,13,14],(‘a’,'b')] a[0]是一个数字不可以修改,a[1]是字符串也不可以修改,a[2]是列表,可以对列表做修改。其实所谓元组不可以修改,可以理解成不能改变每个元素指向的变量的引用值。
>>> a=(12,'ABC',[12,13,14],('a','b'))
>>> a[0]=13
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a[1]='abc'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a[2].append(15)
>>> a
(12, 'ABC', [12, 13, 14, 15], ('a', 'b'))
>>> a[2]=[12,13,21,21,21]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a[3]=('a','c')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
深拷贝和浅拷贝:可以把浅拷贝理解成不彻底的拷贝。而深拷贝则是完全互相不相干的变量,在内存中各自拥有独立的空间。
copy.copy(变量)-->浅拷贝 copy.deepcopy(变量)->深拷贝
对于不可变类型的数字和字符串,深拷贝和浅拷贝没有什么区别。
>>> a=123.123
>>> b=copy.copy(a)
>>> b is a
True
>>> c=copy.deepcopy(a)
>>> c is a
True
>>> a=12.12
>>> b
123.123
>>> c
123.123
>>> m='ABC'
>>> n=copy.copy(m)
>>> n is m
True
>>> s=copy.deepcopy(m)
>>> s is m
True
>>> m='ABCCBDA'
>>> n
'ABC'
>>> s
'ABC'
但是对于元组,情况有点特殊。因为元组里面可能会存储可变类型的变量,例如列表或者字典。
当元组里面只存储了数字和字符串这两种不可变类型的变量,copy和deepcopy没有什么区别。反正这时候的元组是完全不可改变的。
>>> m=(11,22,'AA')
>>> n=copy.copy(m)
>>> t=copy.deepcopy(m)
>>> m is n
True
>>> m is t
True
当元组里面存储了可变类型的变量,copy和deepcopy就不一样了。is 可以判断这两个变量的内存地址是否一样。如下: a和b指向同一块内存地址,但是c是另外一块。
>>> a=(12,'AA',[11,22,33])
>>> b=copy.copy(a)
>>> c=copy.deepcopy(a)
>>> b is a
True
>>> c is a
False
>>> a[2].extend([44,55])
>>> a
(12, 'AA', [11, 22, 33, 44, 55])
>>> b
(12, 'AA', [11, 22, 33, 44, 55])
>>> c
(12, 'AA', [11, 22, 33])
下面再看一下更复杂的情况,当元组里面放的是元组的时候。
>>> m=(11,'A',('a','b'))
>>> n=copy.copy(m)
>>> s=copy.deepcopy(m)
>>> m is n
True
>>> m is s
True
>>> q=(11,'A',('a',('a',[11,12])))
>>> r=copy.deepcopy(q)
>>> t=copy.copy(q)
>>> q is t
True
>>> r is t
False
所以在理解深拷贝和浅拷贝的不同之处之前,我们一定要理解python里面可变类型和不可变类型,尤其是对于元组,可以理解只有当元组里面存储的只有数字或者字符串的时候,它才是真正意义上的不可变类型。最简单的理解就是给你一个元组,这个元组里的值再也不可能改变,那么它的深拷贝和浅拷贝就完全一样了。
真正不可变的元组: (11,23,‘A’)
(11,23,(11,23,'A'))
(11,23,(11,23,('a','b','c')))
值有可能改变的元组: ('a',11,[11,12,13])
('a',11,(11,23,23,[12,21,21]))
下面我们再来讨论一下可变类型的深拷贝和浅拷贝:(以列表为例)
和之前讨论元组类似,对于列表中的不可变元素,浅拷贝完全拷贝了一份新的值,对于可变类型的元素,浅拷贝拷贝该元素的引用,内存中其实还是只存了一份值。只是这里要注意,可变类型的元素包括上面讲的元素值可以改变的元组。对于可变类型的变量,无论深拷贝和浅拷贝都会在内存中开辟一个新的内存空间出来。
>>> import copy
>>> a=[12,'abc',(12,23,34),(12,23,[12,23,24])]
>>> b=copy.copy(a)
>>> c=copy.deepcopy(a)
>>> a is b
False
>>> a is c
False
>>> a[0]=122
>>> a[1]='abcd'
>>> a[2]=(12,23,21,11,21)
>>> a[3][2].append('111')
>>> a
[122, 'abcd', (12, 23, 21, 11, 21), (12, 23, [12, 23, 24, '111'])]
>>> b
[12, 'abc', (12, 23, 34), (12, 23, [12, 23, 24, '111'])]
>>> c
[12, 'abc', (12, 23, 34), (12, 23, [12, 23, 24])]