python赋值和拷贝----一切皆对象,参数皆引用
2017-03-28 14:23
453 查看
目录(?)[-]
摘要
aappend3 ad 1 2 1 2 3 1 2 1 2
1 python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。
2 python参数传递都是“传对象引用”方式。实际上相当于c++中传值和传引用的结合。
3 如果函数收到的是可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。
4 copy模块的copy和deepcopy
目标在于复制对象。
(1)copy.copy
浅拷贝 只复制父对象,对象的内部的子对象依然是引用。
父对象是不同的,但是引用的子对象相同。
>>> d=copy.copy(a)
>>> a.append(8)
>>> a,d
([1, 2, 4, 5, 6, ['a', 'b', 'c'], 7, 8], [1, 2, 4, 5, 6, ['a', 'b', 'c'], 7])
>>> a[5].append('d')
>>> a,d
([1, 2, 4, 5, 6, ['a', 'b', 'c', 'd'], 7, 8], [1, 2, 4, 5, 6, ['a', 'b', 'c', 'd'], 7])
>>>
(2)copy.deepcopy
深拷贝 拷贝对象及其子对象
这意味着引用的父对象和子对象都不同,就是新建了一个对象,建立了引用。相当于传值
>>> a=[1,2,[1,2]]
>>> d=copy.deepcopy(a)
>>> a[2].append(3)
>>> a,d
([1, 2, [1, 2, 3], 3], [1, 2, [1, 2]])
讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用、python的内存管理。
Python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。可能这样说听起来比较难懂,对比一下PHP中的赋值和引用就有大致的概念了。参考下面一段引用:
1.Python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。
2.当人们复制列表或字典时,就复制了对象列表的引用同,如果改变引用的值,则修改了原始的参数。
3.为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。
所谓“传值”也就是赋值的意思了。那么python参数传递有什么特殊呢?看例子:
如果按照PHP的语法,seq和seq_2这两个变量对应两个不同的存储地址,自然对应不同的值,是毫无关联的,但是在python中确令我们大跌眼镜。再看下面的例子:
显然和上面的例子有冲突吗?看开头引用的话就明白了,当引用的原始对象改变的时候,他俩就没有关系了,也就是说他俩是两个不同对象的引用,对应各自引用计数加减1;而第一个例子中seq和seq_2都是对原始对象[1, 2, 3]这个lis对象的引用,所以不管append()还是pop()都不会改变原始对象,只是改变了它的元素,这样也就不难理解第二个例子了,因为b = 2就是创建了一个新的 int 对象。
接下来再通过例子看copy与deepcopy的区别:
这个例子看不出copy之后和之前的联系,也看不出copy与deepcopy的区别。那么再看:
从这就看出来区别了,copy拷贝一个对象,但是对象的属性还是引用原来的,deepcopy拷贝一个对象,把对象里面的属性也做了拷贝,deepcopy之后完全是另一个对象了。再看一个例子:
最后测试你到底掌握没有:
由于我主要从事WEB开发,平时主要用framework里面一下package,很少研究python自身的一些东西,不过话说回来,我是用python来工作的,也不是专门研究这门语言的教授之类。时间越久发现python越有趣。
转自:http://luchanghong.com/python/2012/09/21/the-differences-between-copy-and-deepcopy-in-python.html
目录(?)[-]
摘要
aappend3 ad 1 2 1 2 3 1 2 1 2
1 python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。
2 python参数传递都是“传对象引用”方式。实际上相当于c++中传值和传引用的结合。
3 如果函数收到的是可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。
4 copy模块的copy和deepcopy
目标在于复制对象。
(1)copy.copy
浅拷贝 只复制父对象,对象的内部的子对象依然是引用。
父对象是不同的,但是引用的子对象相同。
>>> d=copy.copy(a)
>>> a.append(8)
>>> a,d
([1, 2, 4, 5, 6, ['a', 'b', 'c'], 7, 8], [1, 2, 4, 5, 6, ['a', 'b', 'c'], 7])
>>> a[5].append('d')
>>> a,d
([1, 2, 4, 5, 6, ['a', 'b', 'c', 'd'], 7, 8], [1, 2, 4, 5, 6, ['a', 'b', 'c', 'd'], 7])
>>>
(2)copy.deepcopy
深拷贝 拷贝对象及其子对象
这意味着引用的父对象和子对象都不同,就是新建了一个对象,建立了引用。相当于传值
>>> a=[1,2,[1,2]]
>>> d=copy.deepcopy(a)
>>> a[2].append(3)
>>> a,d
([1, 2, [1, 2, 3], 3], [1, 2, [1, 2]])
讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用、python的内存管理。
Python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。可能这样说听起来比较难懂,对比一下PHP中的赋值和引用就有大致的概念了。参考下面一段引用:
1.Python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。
2.当人们复制列表或字典时,就复制了对象列表的引用同,如果改变引用的值,则修改了原始的参数。
3.为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。
所谓“传值”也就是赋值的意思了。那么python参数传递有什么特殊呢?看例子:
如果按照PHP的语法,seq和seq_2这两个变量对应两个不同的存储地址,自然对应不同的值,是毫无关联的,但是在python中确令我们大跌眼镜。再看下面的例子:
显然和上面的例子有冲突吗?看开头引用的话就明白了,当引用的原始对象改变的时候,他俩就没有关系了,也就是说他俩是两个不同对象的引用,对应各自引用计数加减1;而第一个例子中seq和seq_2都是对原始对象[1, 2, 3]这个lis对象的引用,所以不管append()还是pop()都不会改变原始对象,只是改变了它的元素,这样也就不难理解第二个例子了,因为b = 2就是创建了一个新的 int 对象。
接下来再通过例子看copy与deepcopy的区别:
这个例子看不出copy之后和之前的联系,也看不出copy与deepcopy的区别。那么再看:
从这就看出来区别了,copy拷贝一个对象,但是对象的属性还是引用原来的,deepcopy拷贝一个对象,把对象里面的属性也做了拷贝,deepcopy之后完全是另一个对象了。再看一个例子:
最后测试你到底掌握没有:
由于我主要从事WEB开发,平时主要用framework里面一下package,很少研究python自身的一些东西,不过话说回来,我是用python来工作的,也不是专门研究这门语言的教授之类。时间越久发现python越有趣。
转自:http://luchanghong.com/python/2012/09/21/the-differences-between-copy-and-deepcopy-in-python.html
摘要
aappend3 ad 1 2 1 2 3 1 2 1 2
摘要:
1 python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。2 python参数传递都是“传对象引用”方式。实际上相当于c++中传值和传引用的结合。
3 如果函数收到的是可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。
4 copy模块的copy和deepcopy
目标在于复制对象。
(1)copy.copy
浅拷贝 只复制父对象,对象的内部的子对象依然是引用。
父对象是不同的,但是引用的子对象相同。
>>> d=copy.copy(a)
>>> a.append(8)
>>> a,d
([1, 2, 4, 5, 6, ['a', 'b', 'c'], 7, 8], [1, 2, 4, 5, 6, ['a', 'b', 'c'], 7])
>>> a[5].append('d')
>>> a,d
([1, 2, 4, 5, 6, ['a', 'b', 'c', 'd'], 7, 8], [1, 2, 4, 5, 6, ['a', 'b', 'c', 'd'], 7])
>>>
(2)copy.deepcopy
深拷贝 拷贝对象及其子对象
这意味着引用的父对象和子对象都不同,就是新建了一个对象,建立了引用。相当于传值
>>> a=[1,2,[1,2]]
>>> d=copy.deepcopy(a)
>>> a.append(3)
>>> a,d
([1, 2, [1, 2], 3], [1, 2, [1, 2]])
>>> a[2].append(3)>>> a,d
([1, 2, [1, 2, 3], 3], [1, 2, [1, 2]])
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
目录(?)[-]
摘要
aappend3 ad 1 2 1 2 3 1 2 1 2
摘要:
1 python中的一切事物皆为对象,并且规定参数的传递都是对象的引用。2 python参数传递都是“传对象引用”方式。实际上相当于c++中传值和传引用的结合。
3 如果函数收到的是可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值”来传递对象。
4 copy模块的copy和deepcopy
目标在于复制对象。
(1)copy.copy
浅拷贝 只复制父对象,对象的内部的子对象依然是引用。
父对象是不同的,但是引用的子对象相同。
>>> d=copy.copy(a)
>>> a.append(8)
>>> a,d
([1, 2, 4, 5, 6, ['a', 'b', 'c'], 7, 8], [1, 2, 4, 5, 6, ['a', 'b', 'c'], 7])
>>> a[5].append('d')
>>> a,d
([1, 2, 4, 5, 6, ['a', 'b', 'c', 'd'], 7, 8], [1, 2, 4, 5, 6, ['a', 'b', 'c', 'd'], 7])
>>>
(2)copy.deepcopy
深拷贝 拷贝对象及其子对象
这意味着引用的父对象和子对象都不同,就是新建了一个对象,建立了引用。相当于传值
>>> a=[1,2,[1,2]]
>>> d=copy.deepcopy(a)
>>> a.append(3)
>>> a,d
([1, 2, [1, 2], 3], [1, 2, [1, 2]])
>>> a[2].append(3)>>> a,d
([1, 2, [1, 2, 3], 3], [1, 2, [1, 2]])
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
相关文章推荐
- python赋值和拷贝----一切皆对象,参数皆引用
- python赋值和拷贝----一切皆对象,参数皆引用
- python赋值和拷贝----一切皆对象,参数皆引用
- python 中的赋值、引用、拷贝、作用域
- python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域
- python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域
- Python中对象的理解:引用和赋值
- python 赋值的时候是引用,如果需要复制则需要注意深拷贝和浅拷贝的区别
- python中的对象拷贝示例 python引用传递
- 深入理解 python 中的赋值、引用、拷贝、作用域
- Python对象赋值、浅拷贝和深拷贝
- python 深入理解 赋值、引用、拷贝、作用域
- WCF实体对象客户端引用时生成多余参数"××Specified",且值类型数据赋值无法传递值时必须付××Specified=true
- python函数参数是值传递还是引用传递(以及变量间复制后是否保持一致):取决于对象内容可变不可变
- 深入理解 python 中的赋值、引用、拷贝、作用域
- python3的对象引用、浅拷贝与深拷贝
- 深入理解 python 中的赋值、引用、拷贝、作用域
- python中的对象拷贝示例 python引用传递
- python函数参数是值传递还是引用传递(以及变量间复制后是否保持一致):取决于对象内容可变不可变
- 深入理解 python 中的赋值、引用、拷贝、作用域