很多人在学python的过程中往往会混淆深拷贝与浅拷贝的概念,深拷贝是对于对象的完全复制,这个好理解。很多人对浅拷贝理解为windows的快捷方式,其实也不尽然…下面的文字将会让你彻底理解他们之间的关系。
先从一道面试题开始:
写出下列代码运行结果:
import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5) [1, 2, 3, 4, ['a', 'b'], 5]
a[4].append('c') ['a', 'b', 'c']
print 'a = ', a [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print 'b = ', b [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print 'c = ', c [1, 2, 3, 4, ['a', 'b', 'c']]
print 'd = ', d [1, 2, 3, 4, ['a', 'b']]
很多人不理解c的输出结果,这正是因为没有深刻理解浅拷贝而容易走进的误区。
先说结论,让我们来一起按图索骥:
- 浅拷贝:对顶层对象引用的拷贝。
- 深拷贝:对一个对象所有层次的拷贝(递归)。【即按照原来的样子在内存中申请空间另外创建一份,与拷贝对象没有任何关系】
示例:
>>> import copy
>>> a = [1,2]
>>> b = [3,4]
>>> c = [a,b]
>>> d = c # d = c相当于增加了对 对象[a,b] 的引用计数
>>> e = copy.copy(c) # e是对c的浅拷贝,即对c顶层对象的拷贝
d = c 与 e = copy.copy(c)的区别?
>>> id(c),id(d),id(e)
(140089296095856, 140089296095856, 140089296096144)
可以看出c
和d
指向同一块内存,e
为另外一块内存区域,所以d=c
仅仅是增加了[a,b]
的引用计数,而e = copy.copy(c)
使系统在内存中另外申请一块内存,用于存放[a,b]
的值.
针对可变与不可变类型的浅拷贝
- 可变类型mutable:列表、字典
>>> import copy
>>> a = [1,2]
>>> b = copy.copy(a)
>>> id(a)
139729228940856
>>> id(b)
139729228503808
浅拷贝对于可变类型而言:在内存重新划分一块区域,其中保存对顶层对象的引用
- 不可变类型immutable:数字、字符串、元组
>>> import copy
>>> a = "amuqiao"
>>> b = copy.copy(a)
>>> id(a)
140663661215344
>>> id(b)
140663661215344
浅拷贝对于不可变类型而言是对被拷贝对象的引用
带着结论回顾第一题
import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5) [1, 2, 3, 4, ['a', 'b'], 5]
a[4].append('c') ['a', 'b', 'c']
print 'a = ', a [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print 'b = ', b [1, 2, 3, 4, ['a', 'b', 'c'], 5]
# 可以得到两点:1.c是对a的浅拷贝;2.a是可变类型,即只保存对a顶层对象的引用。
# 换句话说:在内存中重新划分一块内存,用于保存对a顶层对象的引用,此时id(a)不等于id(c),
# 当a.append(5)的时候,c中保存的"a的顶层对象的引用"的值并没有改变,所以c不变
# 当a[4].append('c')的时候,c中保存的"a的顶层对象的引用"的值['a', 'b']变成了
# ['a', 'b','c'],所以c也改变了
print 'c = ', c [1, 2, 3, 4, ['a', 'b', 'c']]
print 'd = ', d [1, 2, 3, 4, ['a', 'b']]
深拷贝
对一个对象所有层次的拷贝(递归)。【即按照原来的样子在内存中申请空间另外创建一份,与拷贝对象没有任何关系】