前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python copy & deepcopy 区别

python copy & deepcopy 区别

作者头像
bear_fish
发布2018-09-20 14:54:24
9860
发布2018-09-20 14:54:24
举报

[python] view plaincopy

  1. import copy  
  2. # copy 和 deepcopy 的区别
  3. l1 = [1, 2, 3, ['a', 'b']]  
  4. # copy 浅复制,不会拷贝其子对象,修改子对象,将受影响
  5. l2 = copy.copy(l1)  
  6. # deepcopy 深复制,将拷贝其子对象,修改子对象,将不受影响
  7. l3 = copy.deepcopy(l1)  
  8. l1[3].append('c')  
  9. print 'l1:', l1  
  10. print 'l2:', l2  
  11. print 'l3:', l3  

输出: l1: [1, 2, 3, ['a', 'b', 'c']] l2: [1, 2, 3, ['a', 'b', 'c']]

l3: [1, 2, 3, ['a', 'b']]

讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用、python的内存管理。 python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。可能这样说听起来比较难懂。参考下面一段引用: 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] 如果按照传统的观念,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]] 最后测试你到底掌握没有: l = [] d = {'num': 0, 'sqrt': 0} for x in [1, 2, 3]:      d['num'] = x      d['sqrt'] = x*x      l.append(d) print l

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015年04月09日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档