python copy and deeepcopy

来源:互联网 发布:c语言原子锁 编辑:程序博客网 时间:2024/05/18 19:22

感觉看完这个,您对于python的copy理解就会上升一个层次,不再稀里糊涂,赶紧吧

讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用、python的内存管理。

python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。可能这样说听起来比较难懂,对比一下PHP中的赋值和引用就有大致的概念了。参考下面一段引用:

1. python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。2. 当人们复制列表或字典时,就复制了对象列表的引用同,如果改变引用的值,则修改了原始的参数。3. 为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。

所谓“传值”也就是赋值的意思了。那么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, b1 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]]最后测试你到底掌握没有:l = []d = {'num': 0, 'sqrt': 0}for x in [1, 2, 3]:         d['num'] = x     d['sqrt'] = x*x         l.append(d)    print l

查看原文:http://www.zoues.com/index.php/2015/08/27/copy/

0 0
原创粉丝点击