转载:博客
讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用、python的内存管理。
python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。可能这样说听起来比较难懂,对比一下PHP中的赋值和引用就有大致的概念了。参考下面一段引用:所谓“传值”也就是赋值的意思了。那么python参数传递有什么特殊呢?看例子:
>>> seq = [1, 2, 3]
>>> seq_2 = seq
>>> seq_2.append(4)
>>> print seq, seq_2 [1, 2, 3, 4] [1, 2, 3, 4]
>>> seq.append(5)
>>> print seq, seq_2 [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
如果按照PHP的语法,seq和seq_2这两个变量对应两个不同的存储地址,自然对应不同的值,是毫无关联的,但是在python中确令我们大跌眼镜。再看下面的例子:
>>> a = 1
>>> b = a
>>> b = 2
>>> print a, b 1 2
>>> c = (1, 2)
>>> d = c
>>> d = (1, 2, 3)
>>> print c, d (1, 2) (1, 2, 3)
显然和上面的例子有冲突吗?看开头引用的话就明白了,当引用的原始对象改变的时候,他俩就没有关系了,也就是说他俩是两个不同对象的引用,对应各自 引用计数加减1;而第一个例子中seq和seq_2都是对原始对象[1, 2, 3]这个lis对象的引用,所以不管append()还是pop()都不会改变原始对象,只是改变了它的元素,这样也就不难理解第二个例子了,因为b = 2就是创建了一个新的 int 对象。
接下来再通过例子看copy与deepcopy的区别:
>>> seq = [1, 2, 3]
>>> seq_1 = seq
>>> seq_2 = copy.copy(seq)
>>> seq_3 = copy.deepcopy(seq)
>>> seq.append(4)
>>> print seq, seq_1, seq_2, seq_3 [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3] [1, 2, 3]
>>> seq_2.append(5)
>>> print seq, seq_1, seq_2, seq_3 [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 5] [1, 2, 3]
>>> seq_3.append(6)
>>> print seq, seq_1, seq_2, seq_3 [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 5] [1, 2, 3, 6]
这个例子看不出copy之后和之前的联系,也看不出copy与deepcopy的区别。那么再看:
>>> m = [1, ['a'], 2]
>>> m_1 = m
>>> m_2 = copy.copy(m)
>>> m_3 = copy.deepcopy(m)
>>> m[1].append('b')
>>> print m, m_1, m_2, m_3 [1, ['a', 'b'], 2] [1, ['a', 'b'], 2] [1, ['a', 'b'], 2] [1, ['a'], 2] >>> m_2[1].append('c')
>>> print m, m_1, m_2, m_3 [1, ['a', 'b', 'c'], 2] [1, ['a', 'b', 'c'], 2] [1, ['a', 'b', 'c'], 2] [1, ['a'], 2]
>>> m_3[1].append('d')
>>> print m, m_1, m_2, m_3 [1, ['a', 'b', 'c'], 2] [1, ['a', 'b', 'c'], 2] [1, ['a', 'b', 'c'], 2] [1, ['a', 'd'], 2]
从这就看出来区别了,copy拷贝一个对象,但是对象的属性还是引用原来的,deepcopy拷贝一个对象,把对象里面的属性也做了拷贝,deepcopy之后完全是另一个对象了。再看一个例子:
>>> m = [1, [2, 2], [3, 3]]
>>> n = copy.copy(m)
>>> n[1].append(2)
>>> print m, n [1, [2, 2, 2], [3, 3]] [1, [2, 2, 2], [3, 3]]
>>> n[1] = 0
>>> print m, n [1, [2, 2, 2], [3, 3]] [1, 0, [3, 3]]
>>> n[2].append(3)
>>> print m, n [1, [2, 2, 2], [3, 3, 3]] [1, 0, [3, 3, 3]]
>>> m[1].pop() 2
>>> print m, n [1, [2, 2], [3, 3, 3]] [1, 0, [3, 3, 3]]
>>> m[2].pop() 3
>>> print m, n [1, [2, 2], [3, 3]] [1, 0, [3, 3]]