从python中copy与deepcopy的区别看python引用

讨论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, 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

由于我主要从事WEB开发,平时主要用framework里面一下package,很少研究python自身的一些东西,不过话说回来,我是用python来工作的,也不是专门研究这门语言的教授之类。时间越久发现python越有趣。

转载请注明出处,未经允许请勿用作商业用途。本文连接地址:http://luchanghong.com/python/2012/09/21/the-differences-between-copy-and-deepcopy-in-python.html
时间: 2024-11-17 12:44:57

从python中copy与deepcopy的区别看python引用的相关文章

Python 中copy和deepcopy的区别

import copy 假设在python中对list的复制 copy称为浅复制 deepcopy称为深复制 浅复制和深复制在一般的list中作用是相同的,都是进行一个复制 但是在list嵌套list中就会有区别 比如: a = [1,2,[3,4]] b = copy.copy(a) c= copy.deep.copy(a) b就等于[1,2,[3,4]] c就等于[1,2,[3,4]] 但是如果改变b[2][0] = 1 c[2][0] = 2] 改变后b = [1,2,[1,4]] c =

Python字典方法copy()和deepcopy()的区别

1 from copy import deepcopy # import deepcopy模块 2 d = {} 3 d['name'] = ['black', 'guts'] # d = {'name': ['black', 'guts']} 4 c = d.copy() # c = {'name': ['black', 'guts']} 5 dc = deepcopy(d) # dc = {'name': ['black', 'guts']} 6 d['name'].append('whit

Python中浅拷贝和深拷贝的区别

Python中浅拷贝和深拷贝的区别 浅拷贝和深拷贝示意图 如上图,简单点说 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deepcopy 深拷贝 拷贝对象及其子对象 数字,字符串是不可变类型 列表,字典是可变类型 我们看下面的案例 案例一:浅拷贝 >>> import copy     #导入copy模块                >>> s=['name',['savings',100.0]] #赋值给s >

Python中深拷贝与浅拷贝的区别

Python中深拷贝与浅拷贝的区别: 原创 2017年04月20日 16:58:35 标签: python / python两种拷贝 / 深拷贝浅拷贝 / 拷贝区别 1661 定义: 在Python中对象的赋值其实就是对象的引用.当创建一个对象,把它赋值给另一个变量的时候,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已. 浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已.也就是,把对象复制一遍,但是该对象中引用的其他对象我不复制 深拷贝:外围和内部元素都进行了拷贝

Python中的is和==的区别,is判断值是否相等,id判断地址是否一致

Python中的is和==的区别 Python中的对象包含三要素:id.type.value. 其中id用来唯一标示一个对象,type标识对象的类型,value是对象的值. is判断的是a对象是否就是b对象,是通过id来判断的. ==判断的是a对象的值是否和b对象的值相等,是通过value来判断的. 看下边的例子: >>> s=set("1234") >>> s set(['1', '3', '2', '4']) >>> ss=s.

FAQ:Python中*args和**agrs的区别

python提供了两种特别的方法来定义函数的参数: 1. 位置参数 *args,  把参数收集到一个元组中,作为变量args   >>>def show_args(*args):          #定义函数 print args >>>show_agrs("hello", "world")      #调用函数 输出:("hello","world") 2. 关键字参数 **kwargs,

python中linspace()和arange()的区别

python中linspace()和arange()的区别 今天无意间看到linspace(0,4,5)可以产生一个array([0,1,2,3,4])的数组,不知道里面的参数是什么,于是就有了这篇博文. linspace( ) linspace()通过指定开始值.终值和元素个数创建表示等差数列的一维数组,可以通过endpoint参数指定是否包含终值,默认值为True,即包含终值.看如下例子 arange( ) arange()通过指定开始值.终值(不包含终值)和步长创建表示等差数列的一维数组,

Python中type与Object的区别

Python中type与Object的区别 在查看了Python的API后,总算明白了.现在总结如下: 先来看object的说明: Python中关于object的说明很少,甚至只有一句话: class object The most base type 从介绍上看这也是Python对类型统一做出的努力.所以这里的object与Java的Object类有着异曲同工之妙,而且可以推测这个object很可能就是一个定义了一个类型的"空类" 再来看type的说明: class type(ob

python中split()和split(' ')的区别

总结:split()的时候,多个空格当成一个空格:split(' ')的时候,多个空格也要分割,会分割出来空. 例1: 牛客网:牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,"student. a am I".后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是"I am a student.".Cat对一一的翻转这些单词顺序可